SpringDataJpa(四) Specification 动态查询
1)JpaSpecificationExecutor 方法列表:
public interface JpaSpecificationExecutor<T> {
T findOne(Specification<T> var1);
List<T> findAll(Specification<T> var1);
Page<T> findAll(Specification<T> var1, Pageable var2);
List<T> findAll(Specification<T> var1, Sort var2);
long count(Specification<T> var1);
}
- T findOne(Specification var1); 查看单个对象
- List findAll(Specification var1); 查询记录列表
- Page findAll(Specification var1, Pageable var2); 分页查询
- Page: 是springData 封装的pageBean对象,里面包含分页基本属性
- Pageable: 分页条件,接口,构造函数要传入两个参数(当前查询页数,每页记录数)
eg: Pageable pageable = new PageRequest(0, 2);- List findAll(Specification var1, Sort var2); 排序查询
- long count(Specification var1); 统计查询
2)自定义查询:
public interface Specification<T> {
Predicate toPredicate(Root<T> var1, CriteriaQuery<?> var2, CriteriaBuilder var3);
}
- 实现Specification接口
- 实现toPredicate(Root root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) 方法
- root: 查询根对象
- CriteriaQuery: 顶层查询对象,自定义查询方式(了解:一般不用)
- CriteriaBuilder: 查询构造器,封装了基本查询功能
测试:
1.实体类 Customer
/**
* 客户实体类
*/
@Entity
@Table(name = "t_cst_customer")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "cust_id")
private Long custId;
@Column(name = "cust_name")
private String custName;
@Column(name = "cust_industry")
private String custIndustry;
@Column(name = "cust_source")
private String custSource;
@Column(name = "cust_level")
private String custLevel;
@Column(name = "cust_address")
private String custAddress;
@Column(name = "cust_phone")
private String custPhone;
}
2.dao层 CustomerDao
public interface CustomerDao extends JpaRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {
}
3.测试类
1) 单条件精准查询
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath*:applicationContext.xml")
public class SpecTest {
@Autowired
private CustomerDao customerDao;
/**
* 单条件查询
*/
@Test
public void test_findOne(){
/**
* 匿名内部类
* 自定义查询:
* 1.实现Specification 接口(提供泛型,要查询的实体类的类型)
* 2.实现predicate方法(构造查询条件)
* root: 查询的根对象,要查询的任何属性从根对象中获取
* (这个根对象可代表要查询的实体对象)
* criteriaBuilder:查询构造器内部封装了很多查询方法
* eg:equal(path属性, "值") 精准查询
*/
Specification<Customer> specification = new Specification<Customer>() {
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Path<Object> custName = root.get("custName");
// jqpl:from Customer where custName = ?
Predicate predicate = criteriaBuilder.equal(custName, "张三");
return predicate;
}
};
Customer customer = customerDao.findOne(specification);
System.out.println(customer);
}
}
2)多条件精准查询
拼接条件 and | or
/**
* 多条件查询
* 多条件拼接
*/
@Test
public void test_manyCriteria(){
Specification<Customer> specification = new Specification<Customer>() {
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
//1.获取属性
Path<Object> custName = root.get("custName");
Path<Object> custIndustry = root.get("custIndustry");
//2.构造查询条件
Predicate p1 = criteriaBuilder.equal(custName, "张三");
Predicate p2 = criteriaBuilder.equal(custIndustry, "it教育");
//3.拼接条件 and | or
Predicate predicate = criteriaBuilder.and(p1, p2);
return predicate;
}
};
Customer customer = customerDao.findOne(specification);
System.out.println(customer);
}
3)模糊查询
对于 like, gt, ge, lt, le 等查询方式,不能直接传入 path对象,需要说明比较的类型(String, Integer… ) path.as(.class)
/**
* 模糊查询
*/
@Test
public void test_like(){
/**
* 对于 like, gt, ge, lt, le 等查询方式,不能直接传入 path对象
* 还要说明比较的类型(String, Integer... ) path.as(.class)
*/
Specification<Customer> specification = new Specification<Customer>() {
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
//获取要查询的属性
Path<Object> custName = root.get("custName");
//构造查询条件
Predicate predicate = criteriaBuilder.like(custName.as(String.class), "%三%");
return predicate;
}
};
List<Customer> list = customerDao.findAll(specification);
for (Customer customer : list) {
System.out.println(customer);
}
}
4)对排序结果排序
Sort.Direction.DESC 倒序
Sort.Direction.ASC 正序
/**
* 对于 like, gt, ge, lt, le 等查询方式,不能直接传入 path对象
* 还要说明比较的类型(String, Integer... ) path.as(.class)
*/
@Test
public void test_sort(){
Specification<Customer> specification = null;
/**
* 创建排序对象:
* 需要传递参数(排序方式, 排序的属性)
* Sort.Direction.DESC 倒序
* Sort.Direction.ASC 正序
*/
Sort sort = new Sort(Sort.Direction.DESC, "custId");
List<Customer> list = customerDao.findAll(specification, sort);
for (Customer customer : list) {
System.out.println(customer);
}
}
5)分页查询
/**
* 分页查询
* Page<T> findAll(Specification spec, Pageable pageable); 带有条件分页
* Page<T> findAll(Pageable pageable); 不带条件分页
* Page : springData 封装好的pageBean 对象,包含分页的基本属性
* Pageable: 分页条件,接口,构造函数要传入两个参数(当前查询页数,每页记录数)
*
*/
@Test
public void test_page(){
Specification specification = null;
//创建 分页条件对象
Pageable pageable = new PageRequest(0, 2);
Page page = customerDao.findAll(specification, pageable);
//获取记录集合Test
List list = page.getContent();
for (Object o : list) {
System.out.println(o);
}
System.out.println(page.getTotalElements()); //获取总记录数
System.out.println(page.getTotalPages()); //获取总页数
}
}