Jpa之Specifications动态查询

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对应语法
equlefiled = value
gt(greaterThan )filed > value
lt(lessThan)filed < value
ge(greaterThanOrEqualTo )filed >= value
le( lessThanOrEqualTo)filed <= value
notEqulefiled != value
likefiled like value
notLikefiled 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()));
    }
posted @ 2022-10-30 23:22  寒小韩  阅读(1447)  评论(0编辑  收藏  举报