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
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); }
@Repository public interface MyCustomerRepository extends CrudRepository<Customer,Long>, JpaSpecificationExecutor { }
@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); } }
@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