您的位置:首页 > 编程语言 > Java开发

Further study of Spring Data JPA - 深入学习篇(二)

2019-09-30 14:21 489 查看

Further study of Spring Data JPA - 深入学习篇(二)

Spring Data JPA官方文档:https://docs.spring.io/spring-data/jpa/docs/current/reference/html/

可参考的开源项目

  • Spring Data JPA的一系列入门文章
  • Spring For All社区

    -----------------------------------------------------------这是一条性感的分割线-------------------------------------------------------------------------

    在我上一篇文章已经对Spring Data JPA做过了大致上的介绍和分析,Further study of Spring Data JPA - 深入学习篇(一)我们从这篇文章接着对其进行深究,Spring Data JPA为我们提供了JpaSpecificationExecutor接口,只要简单实现toPredicate方法就可以实现复杂的查询,首先我们先看看对JpaSpecificationExecutor接口进行分析:

    JpaSpecificationExecutor源码

    public interface JpaSpecificationExecutor<T> {
    
    Optional<T> findOne(@Nullable Specification<T> spec);
    List<T> findAll(@Nullable Specification<T> spec);
    Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable);
    List<T> findAll(@Nullable Specification<T> spec, Sort sort);
    long count(@Nullable Specification<T> spec);
    }

    Spring Data JPA通过创建方法名做查询,只能做简单的查询,那如果我们需要做一些复杂查询呢?多见见分页和排序怎么办,这里Spring Data JPA为我们提供了其中JpaSpecificationExecutor接口,该接口提供了对JPA Criteria查询(动态查询)的支持,只要简单实现toPredicate方法就可以实现复杂的查询,该接口包含了常用的单个对象、查询数据集合、查询分页数据集合、查询带排序参数的数据集合、查询数据大小、这些都是产业的数据结果集,因此不需要做其他定义即可直接使用,另外,Specification是我们需要传的参数,它也是一个接口:

    public interface Specification<T> extends Serializable {
    long serialVersionUID = 1L;
    
    static <T> Specification<T> not(Specification<T> spec) {
    return Specifications.negated(spec);
    }
    
    static <T> Specification<T> where(Specification<T> spec) {
    return Specifications.where(spec);
    }
    
    default Specification<T> and(Specification<T> other) {
    return Specifications.composed(this, other, CompositionType.AND);
    }
    
    default Specification<T> or(Specification<T> other) {
    return Specifications.composed(this, other, CompositionType.OR);
    }
    
    //提供了toPredicate方法,我们只要按照JPA 2.0 criteria api写好查询条件就可以了
    @Nullable
    Predicate toPredicate(Root<T> var1, CriteriaQuery<?> var2, CriteriaBuilder var3);
    }

    定义MyCustomerRepository,并继承于JpaSpecificationExecutor 接口:

    @Repository
    public interface MyCustomerRepository extends CrudRepository<Customer,Long>, JpaSpecificationExecutor {
    
    }

    MyCustomerService:

    @Service
    public class MyCustomerService {
    
    @Autowired
    MyCustomerRepository repository;
    
    /**
    * 获取分页列表数据
    * @param customer  实体对象
    * @return  返回分页数据
    */
    public Page<Customer> getPageList(Customer customer){
    
    PageRequest pageable = PageRequest.of(1,10,Sort.Direction.ASC);
    
    //使用Specification复杂查询
    return repository.findAll(new Specification() {
    @Override
    public Predicate toPredicate(Root root, CriteriaQuery cq, CriteriaBuilder cb) {
    List<Predicate> predicates = new ArrayList<>();
    if (customer.getId()!=null){
    predicates.add(cb.equal(root.get("id").as(Long.class),customer.getId()));
    }
    if (customer.getFirstName()!=null){
    predicates.add(cb.like(root.get("firstName").as(String.class),customer.getFirstName()));
    }
    if (customer.getFirstName()!=null){
    predicates.add(cb.like(root.get("lastName").as(String.class),customer.getLastName()));
    }
    // todo 具体的业务逻辑实现
    //                return (Predicate) repository.findAll();
    }
    
    },pageable);
    }
    }

    多条件查询

    /**
    * 多条件查询方式一
    * 需求:根据客户firstName和lastName以及年龄条件查询
    */
    public void test1(){
    Specification specification = new Specification() {
    @Override
    public Predicate toPredicate(Root root, CriteriaQuery cq, CriteriaBuilder cb) {
    Predicate predicateCustomerFirstName = cb.equal(root.get("firstNane"),"Bauer");
    Predicate predicateCustomerLastName = cb.equal(root.get("lastName"),"Mdessler");
    Predicate predicateCustomerAge = cb.ge(root.get("age"),20);
    
    List<Predicate> list = new ArrayList<>();
    list.add(predicateCustomerFirstName);
    list.add(predicateCustomerLastName);
    list.add(predicateCustomerAge);
    
    Predicate[] arr = new Predicate[list.size()];
    return cb.and(list.toArray(arr));
    }
    };
    List<Customer> customerList = this.myCustomerRepository.findAll(specification);
    for (Customer customer:customerList){
    System.out.println(customer);
    }
    }
    
    /**
    * 多条件查询方式二
    * 需求:根据客户firstName或年龄或id为10的查询
    */
    public void test2(){
    
    Specification specification = new Specification() {
    @Override
    public Predicate toPredicate(Root root, CriteriaQuery cq, CriteriaBuilder cb) {
    return cb.or(cb.and(cb.equal(root.get("firstName"),"Tony"),
    cb.equal(root.get("id"),5),
    cb.ge(root.get("age"),25)));
    }
    };
    List<Customer> customerList = this.myCustomerRepository.findAll(specification);
    for(Customer customer:customerList){
    System.out.println(customer);
    }
    }

    MyCustomerController添加测试方法

    • 初始化
    @Autowired
    MyCustomerRepository repository;
    • 单一条件查询
    /**
    * 单一查询
    */
    @RequestMapping("/spec1")
    public void specificationQuery1(){
    Specification<Customer> spec = SpecificationFactory.containsLike("lastName","Dessler");
    Pageable pageable = PageRequest.of(0,5, Sort.Direction.ASC,"id");
    
    Page<Customer> page = repository.findAll(spec, pageable);
    System.out.println(page);
    System.out.println(page.getTotalElements());
    System.out.println(page.getTotalPages());
    for (Customer customer:page.getContent()){
    System.out.println(customer.toString());
    }
    }
    • 复合条件查询
    /**
    * 复合条件查询
    */
    @RequestMapping(value = "/spec2")
    public void specificationQuery2(){
    Specification<Customer> spec = Specification
    .where(SpecificationFactory.containsLike("firstName","To"))
    .or(SpecificationFactory.containsLike("lastName","Dess"));
    
    Pageable pageable =  PageRequest.of(0,5,Sort.Direction.DESC,"id");
    
    Page<Customer> page = repository.findAll(spec, pageable);
    System.out.println(page);
    System.out.println(page.getTotalPages());
    System.out.println(page.getTotalElements());
    for (Customer customer:page.getContent()){
    System.out.println(customer.toString());
    }
    }

    至此,使用Specification通过Criteria API进行查询,获得查询的结果集。相较于@Query方式的查询定义,更人性化和方便操作,后面在对Criteria API的使用进一步深入,进一步了解他的底层原理和实现。

  • 内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签:  Spring Spring Data JPA