Spring-datatable-Jpa实现增删改查及分页

废话不多说,先上图,如果是你想要的或者能有所学习就可以接着往下看了。

show.png
前端使用的是插件datatable,外加了一些bootstroop的样式。完成的功能为对数据库的增删改查,页面的模糊查询和分页。源码呈上

1、创建project

在idea中new project-->maven-->右侧选中maven-archetype-webapp,然后一路next,新建的好的项目目录如下
a.png

成型的项目目录如下
b.png

因此需要在main文件夹下新家java,test,testResources三个文件夹,后两个用于测试,并不必需。新建后在file->Project Structure->Modiles页面将新建的文件夹赋予相应的属性,如将java文件夹mark as Sources,这样才能被spring识别。至此,总体结构上便完整了。

2、资源文件配置

1、pom.xml依赖设置
简单而言就是添加项目所需要的jar包,但是maven大大简化了这个过程,只需要将依赖包名按标准加入,剩下的maven自动搞定,推荐一个查询依赖包的网站,http://mvnrepository.com/,只要记得包名就能找到。在该项目下添加的依赖如下,直接copy放入

<dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>4.1.1.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.1.1.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context-support</artifactId>
      <version>4.1.1.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-orm</artifactId>
      <version>4.1.1.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.1.1.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.1.1.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-jpa</artifactId>
      <version>1.7.0.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.8</version>
    </dependency>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-entitymanager</artifactId>
      <version>4.3.7.Final</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.3</version>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.12</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.7.7</version>
    </dependency>
    <dependency>
      <groupId>org.freemarker</groupId>
      <artifactId>freemarker</artifactId>
      <version>2.3.21</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.0.1</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
    <dependency>
      <groupId>org.testng</groupId>
      <artifactId>testng</artifactId>
      <version>6.11</version>
    </dependency>
    <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.8.2</version>
    </dependency>
    <dependency>
      <groupId>javax.persistence</groupId>
      <artifactId>persistence-api</artifactId>
      <version>1.0.2</version>
    </dependency>
    <dependency>
      <groupId>com.mchange</groupId>
      <artifactId>c3p0</artifactId>
      <version>0.9.5-pre9</version>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.38</version>
    </dependency>
</dependencies>

2、配置文件.xml设置
在文件夹下新建一个application.xml(名称无要求),添加代码如下,注解在代码中

<?xml version="1.0" encoding="UTF-8"?>
<beans  xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xmlns:jpa="http://www.springframework.org/schema/data/jpa"
        xsi:schemaLocation="http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                                            http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-3.0.xsd
                                            http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
                                            http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
                                            http://www.springframework.org/schema/mvc  http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
                                            http://www.springframework.org/schema/data/jpa  http://www.springframework.org/schema/data/jpa/spring-jpa-1.8.xsd  ">

        <!--自动扫描(自动注入)-->
        <context:component-scan base-package="com.zhang.Demo" />

        <!--第一步,配置数据源-->
        <bean  id="dataSource"  class="com.mchange.v2.c3p0.ComboPooledDataSource">
                <property  name="driverClass"  value="com.mysql.jdbc.Driver"/>
                <property  name="jdbcUrl"  value="jdbc:mysql:///demo"/><!--jdbc:mysqsl://localhost:3306/xxx-->
                <property  name="user"  value="root"/>
                <property  name="password"  value="wangzhang"/>
                <!--连接池中保留的最大连接数。默认值:  15  -->
                <property  name="maxPoolSize"  value="1000"/>
                <!--  连接池中保留的最小连接数,默认为:3-->
                <property  name="minPoolSize"  value="800"/>
                <!--  初始化连接池中的连接数,取值应在minPoolSize与maxPoolSize之间,默认为3-->
                <property  name="initialPoolSize"  value="500"/>
        </bean>

        <bean  id="entityManagerFactory"
               class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
                <property  name="dataSource"  ref="dataSource"  />
                <property  name="jpaVendorAdapter"  ref="hibernateJpaVendorAdapter"  />
                <property  name="packagesToScan"  value="com.zhang.Demo.entity"  />
                <property  name="jpaProperties">
                        <props>
                                <prop  key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
                                <prop  key="hibernate.show_sql">true</prop>
                                <prop  key="hibernate.hbm2ddl.auto">update</prop>
                        </props>
                </property>
        </bean>

        <bean  id="hibernateJpaVendorAdapter"
               class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property  name="databasePlatform"  value="org.hibernate.dialect.MySQLDialect"  />
        </bean>

        <bean  id="transactionManager"  class="org.springframework.orm.jpa.JpaTransactionManager">
                <property  name="entityManagerFactory"  ref="entityManagerFactory"  />
        </bean>

        <jpa:repositories base-package="com.zhang.Demo.repository"
                          entity-manager-factory-ref="entityManagerFactory"
                          transaction-manager-ref="transactionManager">
        </jpa:repositories>

        <tx:annotation-driven transaction-manager="transactionManager"
                              proxy-target-class="true" />

        <mvc:default-servlet-handler/>
        <mvc:annotation-driven/>
        <mvc:resources mapping="/static/**" location="/WEB-INF/static/"/>
        <mvc:resources location="/WEB-INF/js/" mapping="/js/**"/>
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
                <property name="prefix" value="/WEB-INF/page/"/>
                <property name="suffix" value=".jsp"/>
        </bean>

</beans>

3、web.xml配置
在web.xml中加入过滤器与服务器映射

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <servlet>
    <servlet-name>Demo</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>   <!-- 指明数据库等配置文件的位置 -->
      <param-value>classpath:application.xml</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>Demo</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

</web-app>

至此,项目已经完成一小半了,所有的要用到的配置文件都已经配置好了,剩下的只剩下代码的编写了。

3、后台代码的编写

1、如目录结构,在java下新建一个package,在该package下新建4个package以对应springMVC结构,分别为controller控制层,entity实体层,repository持久层(控制数据库),service服务层。
<1>entity层
该层主要定义实体的字段,@Id定义主键,@GeneratedValue设置自增属性,不必须,但一般有,@Table属性为Jpa的自动建表,设置后会在数据库中自动建立一个名为user的表(数据库还是要自己建的),字段上也可以加各种属性,诸如非空,长度等。

@Entity
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue
    private Integer id;

    private String name;

    private String job;

    private String phone;
    //以下加字段的set 与get方法,alt+insert键弹出快捷窗
}

<2>controller层
加@Controller以注明其为控制层,@RequestMapping注解表示其访问路径。该层主要负责控制,将前端来的访问请求转发到对应的处理service层。第一步,注入service层

    private MyService myService;
    @Autowired
    public void setMyService(MyService myService) {
        this.myService = myService;
    }

这样就可以直接调用seivice层接口,将处理过程交给service层,大幅缩减controller层代码,逻辑更加简明。自动注入之后编写的增删改查代码如下

    @RequestMapping(value="/addOne",method= RequestMethod.GET)
    @ResponseBody
    public User inSave(@ModelAttribute User user)
    {
        myService.save(user);
        return user;
    }

    @RequestMapping(value="/findOne",method= RequestMethod.GET)
    @ResponseBody
    public JSONObject findOne(int id)
    {
        User user = myService.findOne(id);
        JSONObject json = new JSONObject();
        json.put("data",user);
        return json;
    }

    @RequestMapping(value="/deleteById",method= RequestMethod.GET)
    @ResponseBody
    public void deleteById(int id)
    {
        myService.delete(id);
        return ;
    }

    @RequestMapping(value="/modifyOne",method= RequestMethod.GET)
    @ResponseBody
    //WebRequest request, ModelMap model,@RequestBody User user
    public JSONObject modifyOne(@ModelAttribute User user){

        User user1=myService.saveAndFlush(user);
        JSONObject json = new JSONObject();
        json.put("data",user1);
        return json;
    }

看起来是不是很简洁,因为它把所有的业务处理都交给service层了,由于Jpa的相当给力,你会发现service层也相当简洁,如果你没有自定义的一些方法。如果不结合datatable插件,那么查询所有的信息的代码也是很简洁的

    @RequestMapping(value="/findAll",method= RequestMethod.GET)
    @ResponseBody
    public JSONObject findAll()
    {
        List<User> userList = myService.findAll();
        JSONObject json = new JSONObject();
        json.put("data",userList);

        return json;
    }

补充一点,如果不加@ResponseBody注解,那么上图返回的内容为“json.jsp”或者其他网页格式,而不是json格式的字段。
<3>service层
在该层下,一般建立一个service接口与一个serviceImpl实现类,以符合分层思想与层之间以接口链接。

    public interface MyService {

    User save(User user);

    List<User> findAll();

    User findById(int id);

    List<User> findByName(String name);

    User findOne(int id);

    void delete(int id);

    User saveAndFlush(User user);
}

接口的实现类

@Service
@Transactional    //事务标记
public class MyServiceImpl implements MyService{

    private MyRepository myRepository;

    @Autowired
    public void setMyRepository(MyRepository myRepository) {
        this.myRepository = myRepository;
    }

    public User save(User user)
    {
        myRepository.save(user);
        return user;
    }
    
    public List<User> findAll() {
        List<User> all = myRepository.findAll();
        return all;
    }

    public User findById(int id) {
        User user = myRepository.findById(id);
        return user;
    }

    public List<User> findByName(String name) {
        List<User> names = myRepository.findByName(name);
        return names;
    }

    public User findOne(int id) {
        User user=myRepository.findOne(id);
        return user;
    }

    public void delete(int id) {
        myRepository.delete(id);
    }

    public User saveAndFlush(User user) {
        User user1=myRepository.saveAndFlush(user);
        return user1;
    }

<4>reposiory层
也被称为Dao层,主要负责对数据库的操纵,当继承了JpaRepository后,便含有findAll,save,delete等各种自带方法,如果没有也可以使用findByxxx复写方法,程序会自动进行识别查找相应的列,当然也可以加@Query注解完全自写数据库语句。

import com.zhang.Demo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface MyRepository extends JpaRepository<User,Integer>{
    User findById(int id);
    List<User> findByName(String name);
}

至此,后台的业务逻辑处理就基本完成了,源码中还有其他的一些代码,那个是处理前台传输过来的dataTable封装好的json格式数据的,想看完整的功能还是建议参照源码一起看。注:每层的类都需要注明属性,诸如实体层@Entity。

4、与datatable相关的部分前端与后台处理

<1>前端datatable的固定定义代码

    <script>
        $(document).ready( function () {
            var table = $('#myTable').DataTable({
                language: {
                    url: "scripts/zh_CN.txt"
                },
                info: true,
                paging: true,
                bServerSide: true, //是否启动服务器端数据导入
                sAjaxSource: "/demo/tableDemoAjax",         //请求的地址
                fnServerData: retrieveData,           // 获取数据的处理函数
                autoWidth: false,  //禁用自动调整列宽
                stripeClasses: ["odd", "even"],  //为奇偶行加上样式,兼容不支持CSS伪类的场合
                processing: true,  //隐藏加载提示,自行处理
                serverSide: true,  //启用服务器端分页
                searching: false,  //禁用原生搜索
//                orderMulti: true,  //启用多列排序
                order: [],  //取消默认排序查询,否则复选框一列会出现小箭头
                renderer: "bootstrap",  //渲染样式:Bootstrap和jquery-ui
                pagingType: "simple_numbers",  //分页样式:simple,simple_numbers,full,full_numbers
                columnDefs: [{
                    "targets": 'nosort',  //列的样式名
                    "orderable": false    //包含上样式名‘nosort’的禁止排序
                }],

                columns: [
                    {data: 'id'},
                    {data: 'name'},
                    {data: 'job'},
                    {data: 'phone'},
                    {data: function (obj) {
                        op = "<div id='toolbar' class='btn-group'>";
                        op1 = "<button id='btn_edit' type='button' class='btn btn-default' onclick='show_detail(" + obj.id + ");'><span class='glyphicon glyphicon-list' aria-hidden='true'></span>详情</button>";
                        op2 = "<button id='btn_edit' type='button' class='btn btn-default' onclick='show_modify(" + obj.id + ");'><span class='glyphicon glyphicon-pencil' aria-hidden='true'></span>修改</button>";
                        op3 = "<button id='btn_edit' type='button' class='btn btn-default' onclick='show_delete(" + obj.id + ");'><span class='glyphicon glyphicon-remove' aria-hidden='true'></span>删除</button>";
                        op_ = "</div>";
                        return op + op1  + op2  + op3 +op_;
                        }
                    }
                ]
            });

            function retrieveData(sSource, aoData, fnCallback) {
                $.ajax({
                    url: sSource,                              //这个就是请求地址对应sAjaxSource
                    data: {"aoData": JSON.stringify(aoData)},   //这个是把datatable的一些基本数据传给后台,比如起始位置,每页显示的行数 ,分页,排序,查询等的值
                    type: 'GET',
                    dataType: 'json',
                    async: false,
                    success: function (result) {
                        fnCallback(result);                     //把返回的数据传给这个方法就可以了,datatable会自动绑定数据的
                    },
                    error: function (msg) {
                    }
                });
            }
        });
    </script>

sAjaxSource为访问的路径,retrieveData为数据传输定义,一定得是三个参数,上图的sSource就是sAjaxSource里得内容,传输到后台的是一个json字符串,封装的内容有很多,包括分页、排序等参数,详情可以自行百度。
<2>后台处理

 @RequestMapping(value="/tableDemoAjax",method= RequestMethod.GET)
    @ResponseBody
    public String tableDemoAjax(@RequestParam String aoData) {

        DataTableParameter dataTableParam = myService.getDataTableParameterByJsonParam(aoData);

        List<User> userList = myService.findAll();

        int iDisplayEnd=dataTableParam.getiDisplayStart()+dataTableParam.getiDisplayLength();
        if(userList.size()<iDisplayEnd)
            iDisplayEnd=userList.size();

        com.alibaba.fastjson.JSONObject getObj = new com.alibaba.fastjson.JSONObject();
        getObj.put("sEcho", dataTableParam.getsEcho());// 记录访问的次数
        getObj.put("iTotalRecords", userList.size());//实际的行数
        getObj.put("iTotalDisplayRecords", userList.size());//显示的行数,这个要和上面写的一样

        getObj.put("aaData", userList.subList(dataTableParam.getiDisplayStart(),iDisplayEnd));//要以JSON格式返回
        return getObj.toString();
    }

上述的getDataTableParameterByJsonParam(aoData)方法是自写方法,定义在service层的接口,在实现类中实现方法,详情自看源码。

5、结语

一定要参照源码看,这样更容易理解。挂上去的源码只要建个数据库,库名与配置文件中一致就可以直接运行了,向时笔者学习的时候基本上找不到直接能跑的,有的还有各种问题的,给学习增加了不少麻烦。源码
文中如有错误或者更好的建议,请不吝赐教。不理解的也非常欢迎留言交流。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,501评论 25 707
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,748评论 6 342
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,599评论 18 139
  • Android 性能优化 Android性能优化主要有 布局优化、绘制优化、内存泄漏优化、响应速度优化、ListV...
    jiaming_阅读 284评论 0 1
  • 不知道,最近为什么?很喜欢叹气。 不知道,最近为什么?每个人喜欢讨论毕业后的工作。 不知道,最近为什么?总是有下不...
    禾必阅读 227评论 18 2