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

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

u=412711263,4234664486

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

可参考的开源项目java

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

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

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是咱们须要传的参数,它也是一个接口:spring

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的使用进一步深刻,进一步了解他的底层原理和实现。api

相关文章
相关标签/搜索