Spring data jpa的使用与详解(复杂动态查询及分页,排序)

 更新时间:2020年11月01日 09:42:01   作者:耶亚希  
这篇文章主要介绍了Spring data jpa的使用与详解(复杂动态查询及分页,排序),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

一、 使用Specification实现复杂查询

(1) 什么是Specification

Specification是springDateJpa中的一个接口,他是用于当jpa的一些基本CRUD操作的扩展,可以把他理解成一个spring jpa的复杂查询接口。其次我们需要了解Criteria 查询,这是是一种类型安全和更面向对象的查询。而Spring Data JPA支持JPA2.0的Criteria查询,相应的接口是JpaSpecificationExecutor。

而JpaSpecificationExecutor这个接口基本是围绕着Specification接口来定义的,Specification接口中只定义了如下一个方法:

Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb); 

Criteria查询基本概念:

Criteria 查询是以元模型的概念为基础的,元模型是为具体持久化单元的受管实体定义的,这些实体可以是实体类,嵌入类或者映射的父类。

CriteriaQuery接口:

代表一个specific的顶层查询对象,它包含着查询的各个部分,比如:select 、from、where、group by、order by等注意:CriteriaQuery对象只对实体类型或嵌入式类型的Criteria查询起作用。

Root:

代表Criteria查询的根对象,Criteria查询的查询根定义了实体类型,能为将来导航获得想要的结果,它与SQL查询中的FROM子句类似。
Root实例是类型化的,且定义了查询的FROM子句中能够出现的类型。root代表查询的实体类,query可以从中得到root对象,告诉jpa查询哪一个实体类,还可以添加查询条件,还可以结合EntityManager对象 得到最终查询的 TypedQuery对象。

CriteriaBuilder接口:

用来构建CritiaQuery的构建器对象Predicate:一个简单或复杂的谓词类型,其实就相当于条件或者是条件组合。 可通过 EntityManager.getCriteriaBuilder 而得。

二、使用Specification进行复杂的动态查询

maven的依赖继续使用上一章的就可以,这里修改一下实体类和controller层。

请求实体类:

@Data
public class AccountRequest {

  //从第几页开始
  private Integer page;

  //每一页查询多少
  private Integer limit;

  private String id;

  private String name;

  private String pwd;

  private String email;

  private Integer[] types;

}

实体类:

@Data
@Entity
@Table(name = "account")
@ToString
@EntityListeners(AuditingEntityListener.class)
public class Account {

  @Id
  @GenericGenerator(name = "idGenerator", strategy = "uuid")
  @GeneratedValue(generator = "idGenerator")
  private String id;

  @Column(name = "username", unique = true, nullable = false, length = 64)
  private String username;

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

  @Column(name = "email", length = 64)
  private String email;

  @Column(name = "type")
  private Short type;

  @CreatedDate
  @Column(name = "create_time", nullable = false)
  private LocalDateTime createTime;

}

Repository层:

public interface AccountRepository extends JpaRepository<Account,String>, JpaSpecificationExecutor<Account> {}

controller层(还是直接略过service层)

@Autowired
  private AccountRepository repository;


  @PostMapping("/get")
  public List<Account> get(@RequestBody AccountRequest request){
    Specification<Account> specification = new Specification<Account>() {

      @Override
      public Predicate toPredicate(Root<Account> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder builder) {
        //所有的断言 及条件
        List<Predicate> predicates = new ArrayList<>();
        //精确匹配id pwd
        if (request.getId() != null) {
          predicates.add(builder.equal(root.get("id"), request.getId()));
        }
        if (request.getPwd() != null) {
          predicates.add(builder.equal(root.get("password"), request.getPwd()));
        }
        //模糊搜索 name
        if (request.getName() != null && !request.getName().equals("")) {
          predicates.add(builder.like(root.get("username"), "%" + request.getName() + "%"));
        }
        if (request.getEmail() != null && !request.getEmail().equals("")) {
          predicates.add(builder.like(root.get("email"), "%" + request.getEmail() + "%"));
        }
        //in范围查询
        if (request.getTypes() != null) {
          CriteriaBuilder.In<Object> types = builder.in(root.get("type"));
          for (Integer type : request.getTypes()) {
            types = types.value(type);
          }
          predicates.add(types);
        }
        return builder.and(predicates.toArray(new Predicate[predicates.size()]));
      }
    };
    List<Account> accounts = repository.findAll(specification);

    return accounts;
  }

通过重写Specification的toPredicate的方法,这样一个复杂的动态sql查询就完成了,通过post请求直接就可以调用了。

三、分页及排序

@PostMapping("/page")
  public List<Account> getPage(@RequestBody AccountRequest request){

    Specification<Account> specification = new Specification<Account>() {
      @Override
      public Predicate toPredicate(Root<Account> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
        List<Predicate> predicates = new ArrayList<>();
        //do anything
        return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
      }
    };
    //表示通过createTime进行 ASC排序
    PageRequest page = new PageRequest(request.getPage() - 1, request.getLimit(), Sort.Direction.ASC, "createTime");
    Page<Account> pageInfo = repository.findAll(specification, page);

    return pageInfo.getContent();
  }

上面的代码是在经过复杂查询并进行分页与排序,通过PageRequest来构建分页排序的规则。传入起始页及每页的数量,还有排序的规则及以哪个属性排序。jpa中是以第0页开始的,所以传参的时候需要注意!

当然,如果你不需要进行复杂的查询也可以对数据进行分页及排序查询。

修改repository,使其继承PagingAndSortingRepository。

@Repository
public interface AccountRepository extends JpaRepository<Account,String>, JpaSpecificationExecutor<Account> , PagingAndSortingRepository<Account,String> {
  Page<Account> findByAge(int age, Pageable pageable);
}

使用时先创建pageable参数,然后传进去就可以了。

//显示第1页每页显示3条
PageRequest pr = new PageRequest(1,3);
//根据年龄进行查询
Page<Account> stus = accountPageRepository.findByAge(22,pr); 
 

排序也是一样的,在repository中创建方法

List<Account> findByPwd(String pwd, Sort sort);

调用的时候传入sort对象

//设置排序方式为username降序
List<Account> accs = accountPageRepository.findByAge("123456",new Sort(Sort.Direction.DESC,"username"));
//设置排序以username和type进行升序
acc = accountPageRepository.findByAge("123456",new Sort(Sort.Direction.ASC,"username","type"));
//设置排序方式以name升序,以address降序
Sort sort = new Sort(new Sort.Order(Sort.Direction.ASC,"name"),new Sort.Order(Sort.Direction.DESC,"type"));
accs = accountPageRepository.findByAge("123456",sort);

到此这篇关于Spring data jpa的使用与详解(复杂动态查询及分页,排序)的文章就介绍到这了,更多相关Spring data jpa内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot2.x配置多数据源方式

    SpringBoot2.x配置多数据源方式

    这篇文章主要介绍了SpringBoot2.x配置多数据源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03
  • 关于Java 获取时间戳的方法

    关于Java 获取时间戳的方法

    这篇文章主要介绍了关于Java获取时间戳的方法,Java有两个取时间戳的方法,分别是System.currentTimeMillis()和System.nanoTime()下文对两种方法进行详细介绍,需要的小伙伴可以参考一下
    2022-04-04
  • 解决springboot文件配置端口不起作用(默认8080)

    解决springboot文件配置端口不起作用(默认8080)

    这篇文章主要介绍了解决springboot文件配置端口不起作用(默认8080),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • Springboot工具类StringUtils使用教程

    Springboot工具类StringUtils使用教程

    这篇文章主要介绍了Springboot内置的工具类之StringUtils的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2022-12-12
  • SpringBoot disruptor高性能队列使用

    SpringBoot disruptor高性能队列使用

    这篇文章主要介绍了SpringBoot disruptor高性能队列使用,Disruptor是英国外汇交易公司LMAX开发的一个高性能队列,研发的初衷是解决内存队列的延迟问题
    2023-02-02
  • java 高并发中volatile的实现原理

    java 高并发中volatile的实现原理

    这篇文章主要介绍了java 高并发中volatile的实现原理的相关资料,在多线程并发编程中synchronized和Volatile都扮演着重要的角色,Volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的“可见性”,需要的朋友可以参考下
    2017-03-03
  • java的package和import机制原理解析

    java的package和import机制原理解析

    这篇文章主要介绍了java的package和import机制原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01
  • Java关键字instanceof的两种用法实例

    Java关键字instanceof的两种用法实例

    这篇文章主要介绍了Java关键字instanceof的两种用法实例,本文给出了instanceof关键字用于判断一个引用类型变量所指向的对象是否是一个类(或接口、抽象类、父类)及用于数组比较,需要的朋友可以参考下
    2015-03-03
  • java基础的详细了解第一天

    java基础的详细了解第一天

    这篇文章对Java编程语言的基础知识作了一个较为全面的汇总,在这里给大家分享一下。需要的朋友可以参考,希望能给你带来帮助
    2021-08-08
  • 基于Tomcat7、Java、WebSocket的服务器推送聊天室实例

    基于Tomcat7、Java、WebSocket的服务器推送聊天室实例

    HTML5 WebSocket实现了服务器与浏览器的双向通讯,本篇文章主要介绍了基于Tomcat7、Java、WebSocket的服务器推送聊天室实例,具有一定的参考价值,有兴趣的可以了解一下。
    2016-12-12

最新评论