Jpa(四)之動態查詢

Specifications動態查詢

有時我們在查詢某個實體的時候,給定的條件是不固定的,這時就需要動態構建相應的查詢語句,在Spring Data JPA中可以通過JpaSpecificationExecutor接口查詢。相比JPQL,其優勢是類型安全,更加的面向對象。

JpaSpecificationExecutor接口

JpaSpecificationExecutor接口中定義的方法:

import java.util.List;
import java.util.Optional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.lang.Nullable;

public interface JpaSpecificationExecutor<T> {
	//根據條件查詢一個對象
    Optional<T> findOne(@Nullable Specification<T> var1);
	//根據條件查詢對象集合
    List<T> findAll(@Nullable Specification<T> var1);
	//根據條件查詢並進行分頁
     	//pageable :分頁參數
     	//返回值:分頁pageBean,由springdatajpa提供
    Page<T> findAll(@Nullable Specification<T> var1, Pageable var2);
    //排序查詢查詢
         // Sort:排序參數
    List<T> findAll(@Nullable Specification<T> var1, Sort var2);
	//統計查詢
    long count(@Nullable Specification<T> var1);
}

//備註
//	如果可以傳入NULL值,則標記爲@Nullable,如果不可以,則標註爲@Nonnull。

對於JpaSpecificationExecutor,我們可以發現這個接口方法基本是圍繞着Specification接口來定義的。我們可以簡單的理解爲,Specification構造的就是查詢條件。
——>我們需要自定義我們自己的Specification實現類。

Specfication接口

在Specification接口中只定義瞭如下一個方法:

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
//root:查詢的根對象(查詢的任何屬性都可以從根對象中獲取)
//CriteriaQuery:頂層查詢對象,自定義查詢方式(瞭解:一般不用)
//CriteriaBuilder:查詢的構造器,用來構建查詢條件,此對象裏封裝了很多查詢條件方法
public interface Specification<T> {
    Predicate toPredicate(Root<T> var1, CriteriaQuery<?> var2, CriteriaBuilder var3);
}

方法對應關係

方法 SQL對應語法
equle filed = value
gt(greaterThan ) filed > value
lt(lessThan) filed < value
ge(greaterThanOrEqualTo ) filed >= value
le( lessThanOrEqualTo) filed <= value
notEqule filed != value
like filed like value
notLike filed not like value
and 條件1 and 條件2 and 條件3…and 條件n
or 條件1 or 條件2 or 條件3…or 條件n

示例

   /**自定義動態查詢
     *      (1)實例化Specification接口
     *          ——重寫toPredicate方法
     *                * root:獲取需要查詢的對象屬性
     *                *CriteriaBuilder:構建查詢條件的,內部封裝了很多的查詢條件(模糊查詢,精準匹配)
     *      (2)調用JpaSpecificationExecutor接口方法查詢
     *      (3)查詢結果使用
     */

示例1,equal 精確查詢

    @Test
    public void testSpec01(){
        //(1)實現Specification接口
        Specification<Student> spec = new Specification<Student>() {
            @Override
            public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                //1.獲取比較的屬性
                Path<Object> name = root.get("stuName");
                //2.構造查詢條件
                Predicate predicate = criteriaBuilder.equal(name, "趙雲");

                return predicate;
            }
        };

        //(2)調用JpaSpecificationExecutor接口方法查詢
        Optional<Student> optional = repository.findOne(spec);

        // (3)查詢結果使用
        if (optional.isPresent()){
            System.out.println("查詢出結果:"+optional.get());
        }else {
            System.out.println("沒有查詢出結果!!!");
        }
    }

示例2,like 模糊查詢

    /**
     * like 模糊查詢
     */
    @Test
    public void testSpec2(){
        Specification<Student> spec =new Specification<Student>() {
            @Override
            public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {

                Path<Object> name = root.get("stuName");
                Predicate predicate = criteriaBuilder.like(name.as(String.class), "%趙%");
                return predicate;
            }
        };
        List<Student> students = repository.findAll(spec);
        students.forEach(a->System.out.println(a.toString()));

    }

示例3,組合and查詢

    /**
     * 組合查詢
     */
    @Test
    public void testSpec3(){
        Specification<Student> spec =new Specification<Student>() {
            @Override
            public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Object> name = root.get("stuName");
                Path<Object> age = root.get("age");

                Predicate predicate01 = criteriaBuilder.ge(age.as(Integer.class), 20);
                Predicate predicate02 = criteriaBuilder.equal(name,"趙雲");

                Predicate predicate = criteriaBuilder.and(predicate01, predicate02);
                return predicate;
            }
        };

        List<Student> students = repository.findAll(spec);
        students.forEach(a->System.out.println(a.toString()));
    }

示例4,組合or查詢

    /**
     * 組合or查詢
     */
    @Test
    public void testSpec4(){
        Specification<Student> spec =new Specification<Student>() {
            @Override
            public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Object> name = root.get("stuName");
                Path<Object> age = root.get("age");

                Predicate predicate01 = criteriaBuilder.ge(age.as(Integer.class), 20);
                Predicate predicate02 = criteriaBuilder.equal(name,"趙雲");

                Predicate predicate = criteriaBuilder.or(predicate01, predicate02);
                return predicate;
            }
        };
        List<Student> students = repository.findAll(spec);
        students.forEach(a->System.out.println(a.toString()));
    }

示例5,查詢排序

    /**
     * 查詢排序
     */
    @Test
    public void testSpec5(){
        Sort sort =new Sort(Sort.Direction.ASC,"age");

        Specification<Student> spec =new Specification<Student>() {
            @Override
            public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Object> name = root.get("stuName");
                Path<Object> age = root.get("age");

                Predicate predicate01 = criteriaBuilder.ge(age.as(Integer.class), 20);
                Predicate predicate02 = criteriaBuilder.equal(name,"趙雲");

                Predicate predicate = criteriaBuilder.or(predicate01, predicate02);
                return predicate;
            }
        };
        List<Student> students = repository.findAll(spec,sort);
        students.forEach(a->System.out.println(a.toString()));
    }

示例6,查詢分頁

    /**
     * 查詢分頁
     */

    @Test
    public void testSpec6(){
        Sort sort =new Sort(Sort.Direction.ASC,"age");
        PageRequest pageRequest = PageRequest.of(1,2,sort);

        Specification<Student> spec =new Specification<Student>() {
            @Override
            public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Object> name = root.get("stuName");
                Path<Object> age = root.get("age");

                Predicate predicate01 = criteriaBuilder.ge(age.as(Integer.class), 20);
                Predicate predicate02 = criteriaBuilder.equal(name,"趙雲");

                Predicate predicate = criteriaBuilder.or(predicate01, predicate02);
                return predicate;
            }
        };
        Page<Student> studentPage = repository.findAll(spec, pageRequest);
        long totalElements = studentPage.getTotalElements();//獲取全部數量
        System.out.println("供查詢數據量:"+totalElements);
        int totalPages = studentPage.getTotalPages();//獲取全部頁數
        System.out.println("供查詢數據頁數:"+totalElements);
        List<Student> students = studentPage.getContent();//獲取全部內容
        students.forEach(a->System.out.println(a.toString()));
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章