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

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

1、引入起步依赖 

 

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>


2、对thymeleaf和jpa进行配置

打开application.yml,添加以下参数,以下配置在之前的文章中介绍过,此处不做过多说明

spring:
  thymeleaf:
    cache: true
    check-template-location: true
    content-type: text/html
    enabled: true
    encoding: utf-8
    mode: HTML5
    prefix: classpath:/templates/
    suffix: .html
    excluded-view-names:
    template-resolver-order:
  datasource:
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://localhost:3306/restful?useUnicode=true&characterEncoding=UTF-8&useSSL=false
      username: root
      password: root
      initialize: true
  init-db: true
  jpa:
      database: mysql
      show-sql: true
      hibernate:
        ddl-auto: update
        naming:
          strategy: org.hibernate.cfg.ImprovedNamingStrategy

3、编写实体Bean

 

@Entity
@Table(name="book")
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", updatable = false)
    private Long id;

    @Column(nullable = false,name = "name")
    private String name;

    @Column(nullable = false,name = "isbn")
    private String isbn;

    @Column(nullable = false,name = "author")
    private String author;

    public Book (String name,String isbn,String author){
        this.name = name;
        this.isbn = isbn;
        this.author = author;
    }
    public Book(){

    }
    //此处省去get、set方法
}

public class BookQuery {
    private String name;
    private String isbn;
    private String author;
    //此处省去get、set方法
}

  

4、编写Repository接口

@Repository("bookRepository")
public interface BookRepository extends JpaRepository<Book,Long>
        ,JpaSpecificationExecutor<Book> {
}

   

此处继承了两个接口,后续会介绍为何会继承这两个接口

5、抽象service层
首先抽象出接口

 

public interface BookQueryService {
    Page<Book> findBookNoCriteria(Integer page,Integer size);
    Page<Book> findBookCriteria(Integer page,Integer size,BookQuery bookQuery);
}

  

实现接口

 

@Service(value="https://my.oschina.net/wangxincj/blog/bookQueryService")
public class BookQueryServiceImpl implements BookQueryService {
    @Resource
    BookRepository bookRepository;
    @Override
    public Page<Book> findBookNoCriteria(Integer page,Integer size) {
        Pageable pageable = new PageRequest(page, size, Sort.Direction.ASC, "id");
        return bookRepository.findAll(pageable);
    }

    @Override
    public Page<Book> findBookCriteria(Integer page, Integer size, final BookQuery bookQuery) {
        Pageable pageable = new PageRequest(page, size, Sort.Direction.ASC, "id");
        Page<Book> bookPage = bookRepository.findAll(new Specification<Book>(){
            @Override
            public Predicate toPredicate(Root<Book> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                List<Predicate> list = new ArrayList<Predicate>();
                if(null!=bookQuery.getName()&&!"".equals(bookQuery.getName())){
                    list.add(criteriaBuilder.equal(root.get("name").as(String.class), bookQuery.getName()));
                }
                if(null!=bookQuery.getIsbn()&&!"".equals(bookQuery.getIsbn())){
                    list.add(criteriaBuilder.equal(root.get("isbn").as(String.class), bookQuery.getIsbn()));
                }
                if(null!=bookQuery.getAuthor()&&!"".equals(bookQuery.getAuthor())){
                    list.add(criteriaBuilder.equal(root.get("author").as(String.class), bookQuery.getAuthor()));
                }
                Predicate[] p = new Predicate[list.size()];
                return criteriaBuilder.and(list.toArray(p));
            }
        },pageable);
        return bookPage;
    }
}

  

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

findBookCriteria方法也可以使用以下方法实现,大家可以自行选择

 

@Override
    public Page<Book> findBookCriteria(Integer page, Integer size, final BookQuery bookQuery) {
        Pageable pageable = new PageRequest(page, size, Sort.Direction.ASC, "id");
        Page<Book> bookPage = bookRepository.findAll(new Specification<Book>(){
            @Override
            public Predicate toPredicate(Root<Book> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                Predicate p1 = criteriaBuilder.equal(root.get("name").as(String.class), bookQuery.getName());
                Predicate p2 = criteriaBuilder.equal(root.get("isbn").as(String.class), bookQuery.getIsbn());
                Predicate p3 = criteriaBuilder.equal(root.get("author").as(String.class), bookQuery.getAuthor());
                query.where(criteriaBuilder.and(p1,p2,p3));
                return query.getRestriction();
            }
        },pageable);
        return bookPage;
    }

  

6、编写Controller
针对有查询条件和无查询条件,我们分别编写一个Controller,默认每页显示5条,如下

 

@Controller
@RequestMapping(value = "https://my.oschina.net/queryBook")
public class BookController {
    @Autowired
    BookQueryService bookQueryService;

    @RequestMapping("/findBookNoQuery")
    public String findBookNoQuery(ModelMap modelMap,@RequestParam(value = "https://my.oschina.net/wangxincj/blog/page", defaultValue = "https://my.oschina.net/wangxincj/blog/0") Integer page,
                        @RequestParam(value = "https://my.oschina.net/wangxincj/blog/size", defaultValue = "https://my.oschina.net/wangxincj/blog/5") Integer size){
        Page<Book> datas = bookQueryService.findBookNoCriteria(page, size);
        modelMap.addAttribute("datas", datas);
        return "index1";
    }

    @RequestMapping(value = "https://my.oschina.net/findBookQuery",method = {RequestMethod.GET,RequestMethod.POST})
    public String findBookQuery(ModelMap modelMap, @RequestParam(value = "https://my.oschina.net/wangxincj/blog/page", defaultValue = "https://my.oschina.net/wangxincj/blog/0") Integer page,
                                @RequestParam(value = "https://my.oschina.net/wangxincj/blog/size", defaultValue = "https://my.oschina.net/wangxincj/blog/5") Integer size, BookQuery bookQuery){
        Page<Book> datas = bookQueryService.findBookCriteria(page, size,bookQuery);
        modelMap.addAttribute("datas", datas);
        return "index2";
    }
}

  

7、编写页面
首先我们编写一个通用的分页页面,新建一个叫page.html的页面

 

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorator="page">
<body>
<div th:fragment="pager">
    <div class="text-right" th:with="baseUrl=${#httpServletRequest.getRequestURL().toString()},pars=${#httpServletRequest.getQueryString() eq null ? ‘‘ : new String(#httpServletRequest.getQueryString().getBytes(‘iso8859-1‘), ‘UTF-8‘)}">
        <ul style="margin:0px;" class="pagination" th:with="newPar=${new Java.lang.String(pars eq null ? ‘‘ : pars).replace(‘page=‘+(datas.number), ‘‘)},
                                                curTmpUrl=${baseUrl+‘?‘+newPar},
                                                curUrl=${curTmpUrl.endsWith(‘&‘) ? curTmpUrl.substring(0, curTmpUrl.length()-1):curTmpUrl}" >
            <!--<li th:text="${pars}"></li>-->

            <li><a href="https://my.oschina.net/wangxincj/blog/#" th:href="https://my.oschina.net/wangxincj/blog/@{${curUrl}(page=0)}">首页</a></li>
            <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>

            <!--总页数小于等于10-->
            <div th:if="${(datas.totalPages le 10) and (datas.totalPages gt 0)}" th:remove="tag">
                <div th:each="pg : ${#numbers.sequence(0, datas.totalPages - 1)}" th:remove="tag">
                        <span th:if="${pg eq datas.getNumber()}" th:remove="tag">
                            <li class="active"><span class="current_page line_height" th:text="${pg+1}">${pageNumber}</span></li>
                        </span>
                    <span th:unless="${pg eq datas.getNumber()}" th:remove="tag">
                            <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>
                        </span>
                </div>
            </div>

            <!-- 总数数大于10时 -->
            <div th:if="${datas.totalPages gt 10}" th:remove="tag">
                <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>
                <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>
                <li class="active"><span class="current_page line_height" th:text="${datas.number+1}"></span></li>
                <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>
                <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>
            </div>

            <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>
            <!--<li><a href="https://my.oschina.net/wangxincj/blog/#" th:href="https://my.oschina.net/wangxincj/blog/@{${curUrl}(page=${datas.totalPages-1})}">尾页</a></li>-->
            <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>
            <li><span th:utext="‘共‘+${datas.totalPages}+‘页 / ‘+${datas.totalElements}+‘ 条‘"></span></li>
        </ul>
    </div>
</div>
</body>
</html>

  

针对无查询条件的接口,创建一个名为index1.html的页面并引入之前写好的分页页面,如下

 

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8"/>
    <title>Title</title>
    <script type="text/javascript" th:src="https://my.oschina.net/wangxincj/blog/@{/jquery-1.12.3.min.js}"></script>
    <script type="text/javascript" th:src="https://my.oschina.net/wangxincj/blog/@{/bootstrap/js/bootstrap.min.js}"></script>
    <link type="text/css" rel="stylesheet" th:href="https://my.oschina.net/wangxincj/blog/@{/bootstrap/css/bootstrap-theme.min.css}"/>
    <link type="text/css" rel="stylesheet" th:href="https://my.oschina.net/wangxincj/blog/@{/bootstrap/css/bootstrap.css}"/>
</head>
<body>
    <table class="table table-hover">
        <thead>
        <tr>
            <th>ID</th>
            <th>name</th>
            <th>isbn</th>
            <th>author</th>
        </tr>
        </thead>
        <tbody>
        <tr th:each="obj : ${datas}">
            <td th:text="${obj.id}">${obj.id}</td>
            <td th:text="${obj.name}">${obj.name}</td>
            <td th:text="${obj.isbn}">${obj.isbn}</td>
            <td th:text="${obj.name}">${obj.author}</td>
        </tr>
        </tbody>
    </table>
        <div th:include="page :: pager" th:remove="tag"></div>
</body>
</html>

  

针对有查询条件的接口,创建一个名为index2.html的页面并引入之前写好的分页页面,如下 <!DOCTYPE html> <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"/> <title>Title</title> <script type="text/javascript" th:src="https://my.oschina.net/wangxincj/blog/@{/jquery-1.12.3.min.js}"></script> <script type="text/javascript" th:src="https://my.oschina.net/wangxincj/blog/@{/bootstrap/js/bootstrap.min.js}"></script> <link type="text/css" rel="stylesheet" th:href="https://my.oschina.net/wangxincj/blog/@{/bootstrap/css/bootstrap-theme.min.css}"/> <link type="text/css" rel="stylesheet" th:href="https://my.oschina.net/wangxincj/blog/@{/bootstrap/css/bootstrap.css}"/> </head> <body> <form th:action="@{/queryBook/findBookQuery}" th:object="${bookQuery}" th:method="get"> <div class="form-group"> <label class="col-sm-2 control-label" >name</label> <div class="col-sm-4"> <input type="text" class="form-control" id="name" placeholder="请输入名称" th:field="*{name}"/> </div> <label class="col-sm-2 control-label">isbn</label> <div class="col-sm-4"> <input type="text" class="form-control" id="isbn" placeholder="请输ISBN" th:field="*{isbn}"/> </div> </div> <div class="form-group"> <label class="col-sm-2 control-label" >author</label> <div class="col-sm-4"> <input type="text" class="form-control" id="author" placeholder="请输author" th:field="*{author}"/> </div> <div class="col-sm-4"> <button class="btn btn-default" type="submit" placeholder="查询">查询</button> </div> </div> </form> <table class="table table-hover"> <thead> <tr> <th>ID</th> <th>name</th> <th>isbn</th> <th>author</th> </tr> </thead> <tbody> <tr th:each="obj : ${datas}"> <td th:text="${obj.id}">${obj.id}</td> <td th:text="${obj.name}">${obj.name}</td> <td th:text="${obj.isbn}">${obj.isbn}</td> <td th:text="${obj.name}">${obj.author}</td> </tr> </tbody> </table> <div th:include="page :: pager" th:remove="tag"></div> </body> </html>

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

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

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

原文地址:https://www.cnblogs.com/sandea/p/8275890.html

时间: 2024-10-06 20:18:28

在Spring Boot中使用Spring-data-jpa实现分页查询(转)的相关文章

Spring Boot中使用Spring Data JPA示例

JPA是Java Persistence API的简称,是sun公司早期推出的Java持久层规范,目前实现JPA规范的主流框架有Hibernate.OpenJPA等.Hibernate框架是当前较为流行的JPA实现之一,在Spring Data JPA中,默认底层实现也是使用的Hibernate. Spring Data JPA示例搭建 Spring Boot 提供了一个"spring-boot-starter-data-jpa"模块,在项目中使用这个模块,就可以简单的整合Spring

Spring Boot:在Spring Boot中使用Mysql和JPA

本文向你展示如何在Spring Boot的Web应用中使用Mysq数据库,也充分展示Spring Boot的优势(尽可能少的代码和配置).数据访问层我们将使用Spring Data JPA和Hibernate(JPA的实现之一). 1.Maven pom.xml文件 在你的项目中增加如下依赖文件 <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifa

Spring Boot 中的同一个 Bug,竟然把我坑了两次!

真是郁闷,不过这事又一次提醒我解决问题还是要根治,不能囫囵吞枣,否则相同的问题可能会以不同的形式出现,每次都得花时间去搞.刨根问底,一步到位,再遇到类似问题就可以分分钟解决了. 如果大家没看过松哥之前写的 Spring Boot 整合 Spring Session,可以先回顾下: Spring Boot 一个依赖搞定 session 共享,没有比这更简单的方案了! 第一次踩坑 事情是这样的,大概在今年 6 月初的时候,我在项目中使用到了 Session 共享,当时采用的方案就是 Redis+Sp

spring boot 中Spring data jpa数据库表字段命名策略

spring boot 中Spring data jpa命名策略 数据库,表字段命名是驼峰命名法(UserID),Spring data jpa 自动更新之后是 user_id, 表字段不对照, Spring data jpa基于Hibernate5.0 application.properties 写法 1.无修改命名 spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNa

Spring Boot教程35——Spring Data JPA

Hibernate是数据访问解决技术的绝对霸主.JPA是由Hibernate主导的一个基于O/R映射的标准规范.O/R映射即将领域模型类和数据库的表进行映射,通过程序操作对象而实现表数据操作的能力,让数据访问操作无须关注数据库相关的技术. Spring Data JPA介绍 1.定义数据访问层 使用Spring Data JPA建立数据访问层十分简单,只需定义一个继承JpaRepository的接口即可: public interface PersonRepository extends Jpa

Spring Boot:整合Spring Data JPA

综合概述 JPA是Java Persistence API的简称,是一套Sun官方提出的Java持久化规范.其设计目标主要是为了简化现有的持久化开发工作和整合ORM技术,它为Java开发人员提供了一种ORM工具来管理Java应用中的关系数据. 简而言之,JPA提供了使用面向对象的方式操作数据库的功能.JPA充分吸收了现有Hibernate,TopLink,JDO等ORM框架的优势,具有易于使用.伸缩性强等优点. Spring Data JPA是Spring基于Spring Data框架对于JPA

使用spring boot中的JPA操作数据库

前言 Spring boot中的JPA 使用的同学都会感觉到他的强大,简直就是神器一般,通俗的说,根本不需要你写sql,这就帮你节省了很多时间,那么下面我们来一起来体验下这款神器吧. 一.在pom中添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </depen

Spring Boot 中 10 行代码构建 RESTful 风格应用

RESTful ,到现在相信已经没人不知道这个东西了吧!关于 RESTful 的概念,我这里就不做过多介绍了,传统的 Struts 对 RESTful 支持不够友好 ,但是 SpringMVC 对于 RESTful 提供了很好的支持,常见的相关注解有: @RestController @GetMapping @PutMapping @PostMapping @DeleteMapping @ResponseBody ... 这些注解都是和 RESTful 相关的,在移动互联网中,RESTful 得

spring-boot实战【07】【转】:Spring Boot中Web应用的统一异常处理

我们在做Web应用的时候,请求处理过程中发生错误是非常常见的情况.Spring Boot提供了一个默认的映射:/error,当处理中抛出异常之后,会转到该请求中处理,并且该请求有一个全局的错误页面用来展示异常内容. 选择一个之前实现过的Web应用(Chapter3-1-2)为基础,启动该应用,访问一个不存在的URL,或是修改处理内容,直接抛出异常,如: 1 2 3 4 @RequestMapping("/hello") public String hello() throws Exce

springboot(十一):Spring boot中mongodb的使用

mongodb是最早热门非关系数据库的之一,使用也比较普遍,一般会用做离线数据分析来使用,放到内网的居多.由于很多公司使用了云服务,服务器默认都开放了外网地址,导致前一阵子大批 MongoDB 因配置漏洞被攻击,数据被删,引起了人们的注意,感兴趣的可以看看这篇文章:场屠戮MongoDB的盛宴反思:超33000个数据库遭遇入侵勒索,同时也说明了很多公司生产中大量使用mongodb. mongodb简介 MongoDB(来自于英文单词"Humongous",中文含义为"庞大&qu