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()));
}