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

相關文章
相關標籤/搜索