全国报名热线

021-6769 0939

在Spring Boot中使用Spring-data-jpa实现分页查询

时间:2017-12-20 15:38:14   来源:www.07net01.com   阅读:

在我们平时的工作中,查询列表在我们的系统中基本随处可见,那么我们如何使用jpa进行多条件查询以及查询列表分页呢?下面我将介绍两种多条件查询方式。

1、引入起步依赖   
[java] view plain copy
  1. <dependency>  
  2.     <groupId>org.springframework.boot</groupId>  
  3.     <artifactId>spring-boot-starter-web</artifactId>  
  4. </dependency>  
  5. <dependency>  
  6.     <groupId>org.springframework.boot</groupId>  
  7.     <artifactId>spring-boot-starter-thymeleaf</artifactId>  
  8. </dependency>  
  9. <dependency>  
  10.     <groupId>org.springframework.boot</groupId>  
  11.     <artifactId>spring-boot-starter-data-jpa</artifactId>  
  12. </dependency>  


2、对thymeleaf和jpa进行配置
打开application.yml,添加以下参数,以下配置在之前的文章中介绍过,此处不做过多说明
[java] view plain copy
  1. spring:  
  2.   thymeleaf:  
  3.     cache: true  
  4.     check-template-location: true  
  5.     content-type: text/html  
  6.     enabled: true  
  7.     encoding: utf-8  
  8.     mode: HTML5  
  9.     prefix: classpath:/templates/  
  10.     suffix: .html  
  11.     excluded-view-names:  
  12.     template-resolver-order:  
  13.   datasource:  
  14.       driver-class-name: com.mysql.jdbc.Driver  
  15.       url: jdbc:mysql://localhost:3306/restful?useUnicode=true&characterEncoding=UTF-8&useSSL=false  
  16.       username: root  
  17.       password: root  
  18.       initialize: true  
  19.   init-db: true  
  20.   jpa:  
  21.       database: mysql  
  22.       show-sql: true  
  23.       hibernate:  
  24.         ddl-auto: update  
  25.         naming:  
  26.           strategy: org.hibernate.cfg.ImprovedNamingStrategy  

3、编写实体Bean
[java] view plain copy
  1. @Entity  
  2. @Table(name="book")  
  3. public class Book {  
  4.     @Id  
  5.     @GeneratedValue(strategy = GenerationType.IDENTITY)  
  6.     @Column(name = "id", updatable = false)  
  7.     private Long id;  
  8.   
  9.     @Column(nullable = false,name = "name")  
  10.     private String name;  
  11.   
  12.     @Column(nullable = false,name = "isbn")  
  13.     private String isbn;  
  14.   
  15.     @Column(nullable = false,name = "author")  
  16.     private String author;  
  17.   
  18.     public Book (String name,String isbn,String author){  
  19.         this.name = name;  
  20.         this.isbn = isbn;  
  21.         this.author = author;  
  22.     }  
  23.     public Book(){  
  24.   
  25.     }  
  26.     //此处省去get、set方法  
  27. }  
  28.   
  29. public class BookQuery {  
  30.     private String name;  
  31.     private String isbn;  
  32.     private String author;  
  33.     //此处省去get、set方法  
  34. }  


4、编写Repository接口
[java] view plain copy
  1. @Repository("bookRepository")  
  2. public interface BookRepository extends JpaRepository<Book,Long>  
  3.         ,JpaSpecificationExecutor<Book> {  
  4. }  
此处继承了两个接口,后续会介绍为何会继承这两个接口

 

5、抽象service层
首先抽象出接口
[java] view plain copy
  1. public interface BookQueryService {  
  2.     Page<Book> findBookNoCriteria(Integer page,Integer size);  
  3.     Page<Book> findBookCriteria(Integer page,Integer size,BookQuery bookQuery);  
  4. }  
实现接口
[java] view plain copy
  1. @Service(value="https://my.oschina.net/wangxincj/blog/bookQueryService")  
  2. public class BookQueryServiceImpl implements BookQueryService {  
  3.     @Resource  
  4.     BookRepository bookRepository;  
  5.     @Override  
  6.     public Page<Book> findBookNoCriteria(Integer page,Integer size) {  
  7.         Pageable pageable = new PageRequest(page, size, Sort.Direction.ASC, "id");  
  8.         return bookRepository.findAll(pageable);  
  9.     }  
  10.   
  11.     @Override  
  12.     public Page<Book> findBookCriteria(Integer page, Integer size, final BookQuery bookQuery) {  
  13.         Pageable pageable = new PageRequest(page, size, Sort.Direction.ASC, "id");  
  14.         Page<Book> bookPage = bookRepository.findAll(new Specification<Book>(){  
  15.             @Override  
  16.             public Predicate toPredicate(Root<Book> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {  
  17.                 List<Predicate> list = new ArrayList<Predicate>();  
  18.                 if(null!=bookQuery.getName()&&!"".equals(bookQuery.getName())){  
  19.                     list.add(criteriaBuilder.equal(root.get("name").as(String.class), bookQuery.getName()));  
  20.                 }  
  21.                 if(null!=bookQuery.getIsbn()&&!"".equals(bookQuery.getIsbn())){  
  22.                     list.add(criteriaBuilder.equal(root.get("isbn").as(String.class), bookQuery.getIsbn()));  
  23.                 }  
  24.                 if(null!=bookQuery.getAuthor()&&!"".equals(bookQuery.getAuthor())){  
  25.                     list.add(criteriaBuilder.equal(root.get("author").as(String.class), bookQuery.getAuthor()));  
  26.                 }  
  27.                 Predicate[] p = new Predicate[list.size()];  
  28.                 return criteriaBuilder.and(list.toArray(p));  
  29.             }  
  30.         },pageable);  
  31.         return bookPage;  
  32.     }  
  33. }  

    此处我定义了两个接口,findBookNoCriteria是不带查询条件的,findBookCriteria是带查询条件的。在此处介绍一下上面提到的自定义Repository继承的两个接口,如果你的查询列表是没有查询条件,只是列表展示和分页,只需继承JpaRepository接口即可,但是如果你的查询列表是带有多个查询条件的话则需要继承JpaSpecificationExecutor接口,这个接口里面定义的多条件查询的方法。当然不管继承哪个接口,当你做分页查询时,都是需要调用findAll方法的,这个方法是jap定义好的分页查询方法。

findBookCriteria方法也可以使用以下方法实现,大家可以自行选择
[java] view plain copy
  1. @Override  
  2.     public Page<Book> findBookCriteria(Integer page, Integer size, final BookQuery bookQuery) {  
  3.         Pageable pageable = new PageRequest(page, size, Sort.Direction.ASC, "id");  
  4.         Page<Book> bookPage = bookRepository.findAll(new Specification<Book>(){  
  5.             @Override  
  6.             public Predicate toPredicate(Root<Book> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {  
  7.                 Predicate p1 = criteriaBuilder.equal(root.get("name").as(String.class), bookQuery.getName());  
  8.                 Predicate p2 = criteriaBuilder.equal(root.get("isbn").as(String.class), bookQuery.getIsbn());  
  9.                 Predicate p3 = criteriaBuilder.equal(root.get("author").as(String.class), bookQuery.getAuthor());  
  10.                 query.where(criteriaBuilder.and(p1,p2,p3));  
  11.                 return query.getRestriction();  
  12.             }  
  13.         },pageable);  
  14.         return bookPage;  
  15.     }  

6、编写Controller
针对有查询条件和无查询条件,我们分别编写一个Controller,默认每页显示5条,如下
[java] view plain copy
  1. @Controller  
  2. @RequestMapping(value = "https://my.oschina.net/queryBook")  
  3. public class BookController {  
  4.     @Autowired  
  5.     BookQueryService bookQueryService;  
  6.   
  7.     @RequestMapping("/findBookNoQuery")  
  8.     public String findBookNoQuery(ModelMap modelMap,@RequestParam(value = "https://my.oschina.net/wangxincj/blog/page", defaultValue = "https://my.oschina.net/wangxincj/blog/0") Integer page,  
  9.                         @RequestParam(value = "https://my.oschina.net/wangxincj/blog/size", defaultValue = "https://my.oschina.net/wangxincj/blog/5") Integer size){  
  10.         Page<Book> datas = bookQueryService.findBookNoCriteria(page, size);  
  11.         modelMap.addAttribute("datas", datas);  
  12.         return "index1";  
  13.     }  
  14.   
  15.     @RequestMapping(value = "https://my.oschina.net/findBookQuery",method = {RequestMethod.GET,RequestMethod.POST})  
  16.     public String findBookQuery(ModelMap modelMap, @RequestParam(value = "https://my.oschina.net/wangxincj/blog/page", defaultValue = "https://my.oschina.net/wangxincj/blog/0") Integer page,  
  17.                                 @RequestParam(value = "https://my.oschina.net/wangxincj/blog/size", defaultValue = "https://my.oschina.net/wangxincj/blog/5") Integer size, BookQuery bookQuery){  
  18.         Page<Book> datas = bookQueryService.findBookCriteria(page, size,bookQuery);  
  19.         modelMap.addAttribute("datas", datas);  
  20.         return "index2";  
  21.     }  
  22. }  


7、编写页面
首先我们编写一个通用的分页页面,新建一个叫page.html的页面
[html] view plain copy
  1. <!DOCTYPE html>  
  2. <html xmlns="http://www.w3.org/1999/xhtml"  
  3.       xmlns:th="http://www.thymeleaf.org"  
  4.       xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"  
  5.       layout:decorator="page">  
  6. <body>  
  7. <div th:fragment="pager">  
  8.     <div class="text-right" th:with="baseUrl=${#httpServletRequest.getRequestURL().toString()},pars=${#httpServletRequest.getQueryString() eq null ? '' : new String(#httpServletRequest.getQueryString().getBytes('iso8859-1'), 'UTF-8')}">  
  9.         <ul style="margin:0px;" class="pagination" th:with="newPar=${new Java.lang.String(pars eq null ? '' : pars).replace('page='+(datas.number), '')},  
  10.                                                 curTmpUrl=${baseUrl+'?'+newPar},  
  11.                                                 curUrl=${curTmpUrl.endsWith('&') ? curTmpUrl.substring(0, curTmpUrl.length()-1):curTmpUrl}" >  
  12.             <!--<li th:text="${pars}"></li>-->  
  13.   
  14.             <li><a href="https://my.oschina.net/wangxincj/blog/#" th:href="https://my.oschina.net/wangxincj/blog/@{${curUrl}(page=0)}">首页</a></li>  
  15.             <li th:if="${datas.hasPrevious()}"><a href="https://my.oschina.net/wangxincj/blog/#" th:href="https://my.oschina.net/wangxincj/blog/@{${curUrl}(page=${datas.number-1})}">上一页</a></li>  
  16.   
  17.             <!--总页数小于等于10-->  
  18.             <div th:if="${(datas.totalPages le 10) and (datas.totalPages gt 0)}" th:remove="tag">  
  19.                 <div th:each="pg : ${#numbers.sequence(0, datas.totalPages - 1)}" th:remove="tag">  
  20.                         <span th:if="${pg eq datas.getNumber()}" th:remove="tag">  
  21.                             <li class="active"><span class="current_page line_height" th:text="${pg+1}">${pageNumber}</span></li>  
  22.                         </span>  
  23.                     <span th:unless="${pg eq datas.getNumber()}" th:remove="tag">  
  24.                             <li><a href="https://my.oschina.net/wangxincj/blog/#" th:href="https://my.oschina.net/wangxincj/blog/@{${curUrl}(page=${pg})}" th:text="${pg+1}"></a></li>  
  25.                         </span>  
  26.                 </div>  
  27.             </div>  
  28.   
  29.             <!-- 总数数大于10时 -->  
  30.             <div th:if="${datas.totalPages gt 10}" th:remove="tag">  
  31.                 <li th:if="${datas.number-2 ge 0}"><a href="https://my.oschina.net/wangxincj/blog/#" th:href="https://my.oschina.net/wangxincj/blog/@{${curUrl}(page=${datas.number}-2)}" th:text="${datas.number-1}"></a></li>  
  32.                 <li th:if="${datas.number-1 ge 0}"><a href="https://my.oschina.net/wangxincj/blog/#" th:href="https://my.oschina.net/wangxincj/blog/@{${curUrl}(page=${datas.number}-1)}" th:text="${datas.number}"></a></li>  
  33.                 <li class="active"><span class="current_page line_height" th:text="${datas.number+1}"></span></li>  
  34.                 <li th:if="${datas.number+1 lt datas.totalPages}"><a href="https://my.oschina.net/wangxincj/blog/#" th:href="https://my.oschina.net/wangxincj/blog/@{${curUrl}(page=${datas.number}+1)}" th:text="${datas.number+2}"></a></li>  
  35.                 <li th:if="${datas.number+2 lt datas.totalPages}"><a href="https://my.oschina.net/wangxincj/blog/#" th:href="https://my.oschina.net/wangxincj/blog/@{${curUrl}(page=${datas.number}+2)}" th:text="${datas.number+3}"></a></li>  
  36.             </div>  
  37.   
  38.   
  39.             <li th:if="${datas.hasNext()}"><a href="https://my.oschina.net/wangxincj/blog/#" th:href="https://my.oschina.net/wangxincj/blog/@{${curUrl}(page=${datas.number+1})}">下一页</a></li>  
  40.             <!--<li><a href="https://my.oschina.net/wangxincj/blog/#" th:href="https://my.oschina.net/wangxincj/blog/@{${curUrl}(page=${datas.totalPages-1})}">尾页</a></li>-->  
  41.             <li><a href="https://my.oschina.net/wangxincj/blog/#" th:href="https://my.oschina.net/wangxincj/blog/${datas.totalPages le 0 ? curUrl+'page=0':curUrl+'&page='+(datas.totalPages-1)}">尾页</a></li>  
  42.             <li><span th:utext="'共'+${datas.totalPages}+'页 / '+${datas.totalElements}+' 条'"></span></li>  
  43.         </ul>  
  44.     </div>  
  45. </div>  
  46. </body>  
  47. </html>  
针对无查询条件的接口,创建一个名为index1.html的页面并引入之前写好的分页页面,如下
[html] view plain copy
  1. <!DOCTYPE html>  
  2. <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">  
  3. <head>  
  4.     <meta charset="UTF-8"/>  
  5.     <title>Title</title>  
  6.     <script type="text/javascript" th:src="https://my.oschina.net/wangxincj/blog/@{/jquery-1.12.3.min.js}"></script>  
  7.     <script type="text/javascript" th:src="https://my.oschina.net/wangxincj/blog/@{/bootstrap/js/bootstrap.min.js}"></script>  
  8.     <link type="text/css" rel="stylesheet" th:href="https://my.oschina.net/wangxincj/blog/@{/bootstrap/css/bootstrap-theme.min.css}"/>  
  9.     <link type="text/css" rel="stylesheet" th:href="https://my.oschina.net/wangxincj/blog/@{/bootstrap/css/bootstrap.css}"/>  
  10. </head>  
  11. <body>  
  12.     <table class="table table-hover">  
  13.         <thead>  
  14.         <tr>  
  15.             <th>ID</th>  
  16.             <th>name</th>  
  17.             <th>isbn</th>  
  18.             <th>author</th>  
  19.         </tr>  
  20.         </thead>  
  21.         <tbody>  
  22.         <tr th:each="obj : ${datas}">  
  23.             <td th:text="${obj.id}">${obj.id}</td>  
  24.             <td th:text="${obj.name}">${obj.name}</td>  
  25.             <td th:text="${obj.isbn}">${obj.isbn}</td>  
  26.             <td th:text="${obj.name}">${obj.author}</td>  
  27.         </tr>  
  28.         </tbody>  
  29.     </table>  
  30.         <div th:include="page :: pager" th:remove="tag"></div>  
  31. </body>  
  32. </html>  
  33.   
  34.      针对有查询条件的接口,创建一个名为index2.html的页面并引入之前写好的分页页面,如下  
  35.   
  36. <!DOCTYPE html>  
  37. <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">  
  38. <head>  
  39.     <meta charset="UTF-8"/>  
  40.     <title>Title</title>  
  41.     <script type="text/javascript" th:src="https://my.oschina.net/wangxincj/blog/@{/jquery-1.12.3.min.js}"></script>  
  42.     <script type="text/javascript" th:src="https://my.oschina.net/wangxincj/blog/@{/bootstrap/js/bootstrap.min.js}"></script>  
  43.     <link type="text/css" rel="stylesheet" th:href="https://my.oschina.net/wangxincj/blog/@{/bootstrap/css/bootstrap-theme.min.css}"/>  
  44.     <link type="text/css" rel="stylesheet" th:href="https://my.oschina.net/wangxincj/blog/@{/bootstrap/css/bootstrap.css}"/>  
  45. </head>  
  46. <body>  
  47. <form th:action="@{/queryBook/findBookQuery}" th:object="${bookQuery}" th:method="get">  
  48.     <div class="form-group">  
  49.         <label class="col-sm-2 control-label" >name</label>  
  50.         <div class="col-sm-4">  
  51.             <input type="text" class="form-control" id="name" placeholder="请输入名称" th:field="*{name}"/>  
  52.         </div>  
  53.         <label class="col-sm-2 control-label">isbn</label>  
  54.         <div class="col-sm-4">  
  55.             <input type="text" class="form-control" id="isbn" placeholder="请输ISBN" th:field="*{isbn}"/>  
  56.         </div>  
  57.     </div>  
  58.     <div class="form-group">  
  59.         <label class="col-sm-2 control-label" >author</label>  
  60.         <div class="col-sm-4">  
  61.             <input type="text" class="form-control" id="author" placeholder="请输author" th:field="*{author}"/>  
  62.         </div>  
  63.         <div class="col-sm-4">  
  64.             <button class="btn btn-default" type="submit" placeholder="查询">查询</button>  
  65.         </div>  
  66.     </div>  
  67. </form>  
  68.     <table class="table table-hover">  
  69.         <thead>  
  70.         <tr>  
  71.             <th>ID</th>  
  72.             <th>name</th>  
  73.             <th>isbn</th>  
  74.             <th>author</th>  
  75.         </tr>  
  76.         </thead>  
  77.         <tbody>  
  78.         <tr th:each="obj : ${datas}">  
  79.             <td th:text="${obj.id}">${obj.id}</td>  
  80.             <td th:text="${obj.name}">${obj.name}</td>  
  81.             <td th:text="${obj.isbn}">${obj.isbn}</td>  
  82.             <td th:text="${obj.name}">${obj.author}</td>  
  83.         </tr>  
  84.         </tbody>  
  85.     </table>  
  86.         <div th:include="page :: pager" th:remove="tag"></div>  
  87. </body>  
  88. </html>  

ok!代码都已经完成,我们将项目启动起来,看一下效果。大家可以往数据库中批量插入一些数据,访问http://localhost:8080/queryBook/findBookNoQuery,显示如下页面

访问http://localhost:8080/queryBook/findBookQuery,显示页面如下,可以输入查询条件进行带条件的分页查询:

ok!以上便是一个简单的jap分页查询功能的实现。

分享:0