JpaSpecificationExecutor 接口


一、JpaSpecificationExecutor 接口介绍

1、该接口主要提供了多条件查询的支持,并且可以在查询中添加分页与排序。(之前 PagingAndSortingRepository 接口进行分页和排序的前提条件是 findAll 查询全部。)

2、JpaSpecificationExecutor 是单独存在的、跟之前的继承关系扯不上。独立公关人。

3、一般开发中,都是将 JpaSpecificationExecutor 接口与 JpaRepository 接口配合使用来完成开发。


二、JpaSpecificationExecutor 接口使用

2.1 编写 /src/main/java/cn/yangdh/dao/UsersRepositorySpecification.java 接口

package cn.yangdh.dao;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

import cn.yangdh.pojo.Users;

/**
 * 该接口 继承了两个接口:JpaRepository接口  、JpaSpecificationExecutor接口
 * 
 * @author *****
 *
 */
public interface UsersRepositorySpecification extends JpaRepository<Users, Integer> ,JpaSpecificationExecutor<Users>{
	
}

2.2 编写测试 /src/test/java/cn/yangdh/test/UsersRepositoryTest.java

单条件查询:

//注入 JPASpecificationExecutor  接口
@Autowired
private UsersRepositorySpecification usersRepositorySpecification;

/*
 * JpaSpecificationExecutor 接口  
 * 
 * 单条件查询  测试
 * demo: where name = "许知远"
 */
@Test
public void testJpaSpecificationExecutor1(){

    /*
	 * Specification<Users> 该对象用于封装要查询的条件的。
	 * 
	 */
    Specification<Users> spec = new Specification<Users>() {

        /*
		 * Predicate :该对象封装了单个的查询条件、即一个Predicate 就是一个查询条件。
		 * 参数Root<Users> 查询对象的属性的封装
		 * 参数CriteriaQuery<?> 封装了要执行的查询中的各个部分的信息(eg:select from order by)
		 * 参数CriteriaBuilde 查询条件的构造器、帮助我们定义不同的查询条件的。
		 */
        @Override
        public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            // eg:where name = "许知远"
            // 做相等判断
            /*
			* 参数一:查询的条件的属性、但是需要从root里去取出 
			* 参数二:条件的值
			* 单条件查询:查询name为许知远的Users
			*/
            Predicate pre = cb.equal(root.get("name"), "许知远");//需要从root里去取出
            return pre;
        }
    };

    List<Users> list = this.usersRepositorySpecification.findAll(spec);
    for (Users users : list) {
        System.out.println(users);
    }
}

多条件查询(方式一、即创建 Predicate 集合 ):

/*
 * JpaSpecificationExecutor 接口  
 * 
 * 多条件查询  测试
 * 区别在于 toPredicate 方法内不同、即创建 Predicate 集合
 * demo: where name = "许知远" and age = 43; 多条件指的是这个意思,比如and、or等
 */
@Test
public void testJpaSpecificationExecutor2(){

    /*
	 * Specification<Users> 该对象用于封装要查询的条件的。
	 * 
	 */
    Specification<Users> spec = new Specification<Users>() {

        /*
		 * Predicate :该对象封装了单个的查询条件、即一个Predicate 就是一个查询条件。
		 * 参数Root<Users> 查询对象的属性的封装
		 * 参数CriteriaQuery<?> 封装了要执行的查询中的各个部分的信息(eg:select from order by)
		 * 参数CriteriaBuilde 查询条件的构造器、帮助我们定义不同的查询条件的。
		 */
        @Override
        public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

            //eg: where name = "许知远" and age = 43;
            List<Predicate> list = new ArrayList<Predicate>();
            //两个 Predicate
            list.add(cb.equal(root.get("name"), "许知远"));
            list.add(cb.equal(root.get("age"), 43));
            //给定这两个条件的关系
            Predicate[] preArr = new Predicate[list.size()]; //构建数组
            Predicate pre = cb.and(list.toArray(preArr));//and方法参数为 Predicate的数组、同时list 转换成数组 内部参数也为Predicate 数组

            return pre;
        }
    };

    List<Users> list = this.usersRepositorySpecification.findAll(spec);
    for (Users users : list) {
        System.out.println(users);
    }
}

多条件查询(方式二、 不用list集合,and 或 or …等方法的参数列表里 直接按数组的形式放进去即可、用逗号隔开):

/*
 * JpaSpecificationExecutor 接口  
 * 
 * 多条件查询  测试    方式二
 * demo: where name = "许知远" and age = 43 or age = 0;
 * 即  where ((name = "许知远" and age = 43) or age = 0);
 */
@Test
public void testJpaSpecificationExecutor3(){

    /*
	 * Specification<Users> 该对象用于封装要查询的条件的。
	 * 
	 */
    Specification<Users> spec = new Specification<Users>() {

        /*
		 * Predicate :该对象封装了单个的查询条件、即一个Predicate 就是一个查询条件。
		 * 参数Root<Users> 查询对象的属性的封装
		 * 参数CriteriaQuery<?> 封装了要执行的查询中的各个部分的信息(eg:select from order by)
		 * 参数CriteriaBuilde 查询条件的构造器、帮助我们定义不同的查询条件的。
		 */
        @Override
        public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

            //如果是 and 查询
            //return cb.and(cb.equal(root.get("name"), "许知远"), cb.equal(root.get("age"), 43));
            
            //如果是 or 查询
            //return cb.or(cb.equal(root.get("name"), "许知远"), cb.equal(root.get("age"), 43));
            
            //如果既有 and 又有 or 查询(原则: 先考虑and 、再考虑or)
            //name = "许知远" and age = 43 or age = 0   (说明:and优先级高于 or)
            return cb.or(cb.and(cb.equal(root.get("name"), "许知远"), cb.equal(root.get("age"), 43) ), cb.equal(root.get("age"), 0));
        }
    };

    List<Users> list = this.usersRepositorySpecification.findAll(spec);
    for (Users users : list) {
        System.out.println(users);
    }
}