SpringDataJPA中的dao层接口继承了JpaRepository接口和JpaSpecificationExecutor接口。
- JpaRepository接口主要是实现了简单的增删改查,上篇文章已经做了案例解析,具体请参考上篇文章:Spring Data JPA快速入门案例,Spring整合Spring Data JPA配置文件约束
- JpaSpecificationExecutor接口是实现了复杂的动态查询,比如多条件、排序、分页等,今天我们就来学习下它,因为我是在入门案例的基础上继续学习的,具体搭建环境的方法请参考上篇文章:Spring Data JPA快速入门案例,Spring整合Spring Data JPA配置文件约束
JpaSpecificationExecutor接口主要的方法有:
- findOne(根据动态条件查询一条数据)
- findAll(根据动态条件查询多条数据、可排序、可分页)
- count(根据动态条件查询数据量)
直接贴测试代码吧,具体备注在代码中有注明
package cn.gpxxg.test;
import cn.gpxxg.dao.ICustomerDao;
import cn.gpxxg.domain.Customer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.persistence.criteria.*;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class) // 表明使用spring的测试类
@ContextConfiguration(locations = "classpath:applicationContext.xml") // 读取spring的配置文件
public class JpaSpecificationTest {
@Autowired
private ICustomerDao dao;
/**
* 使用JpaSpecificationExecutor的findOne,查询一条数据
* 案例:查询id为1的数据
*/
@Test
public void findOneTest()
{
/**
* 匿名内部类
* 自定义查询条件
* 1、实现Specification接口(提供泛型,查询的对象实体类)
* 2、实现toPredicate方法(该方法用于构造查询条件)
* 3、需要借助方法中的两个参数
* Root<T> root:获取需要查询的对象属性
* CriteriaQuery<T> query:顶层查询对象(了解,一般不用)
* CriteriaBuilder cb:构造查询条件,内容封装了很多查询方式(模糊匹配、精准匹配...)
*
*/
Specification<Customer> spe = new Specification<Customer>() {
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
Path<Object> id = root.get("id");
Predicate predicate = cb.equal(id, 1);
return predicate;
}
};
Customer one = dao.findOne(spe);
System.out.println(one);
}
/**
* 使用JpaSpecificationExecutor的findAll,根据客户名模糊查询
*/
@Test
public void findAllTest1()
{
/**
* 匿名内部类
* 自定义查询条件
* 1、实现Specification接口(提供泛型,查询的对象实体类)
* 2、实现toPredicate方法(该方法用于构造查询条件)
* 3、需要借助方法中的两个参数
* Root<T> root:获取需要查询的对象属性
* CriteriaQuery<T> query:顶层查询对象(了解,一般不用)
* CriteriaBuilder cb:构造查询条件,内容封装了很多查询方式(模糊匹配、精准匹配...)
*
*/
Specification<Customer> spe = new Specification<Customer>() {
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
// 1、获取比较对象的属性
Path<Object> custName = root.get("custName");
// 2、定义查询方式:select * from customer where cust_name = '马德华'
Predicate predicate = cb.equal(custName, "马德华");
return predicate;
}
};
// 传入条件,获取数据列表
List<Customer> list = dao.findAll(spe);
for (Customer customer : list) {
System.out.println(customer);
}
}
/**
* 使用JpaSpecificationExecutor的findAll多条件查询,根据客户名模糊查询、客户地址精准查询
* 注意:使用模糊查询时,需要告知参数的数据类型(String、Integer)
*/
@Test
public void findAllTest2()
{
Specification spe = new Specification() {
public Predicate toPredicate(Root root, CriteriaQuery cq, CriteriaBuilder cb) {
// 1、获取比较对象的属性
Path custName = root.get("custName");
Path custAddress = root.get("custAddress");
// 2、定义查询方式:select * from customer where cust_name like '%马德华%' and cust_address = '西游记'
Predicate p1 = cb.like(custName.as(String.class), "%马德华%");
Predicate p2 = cb.equal(custAddress, "西游记");
// 3、连接多个查询,返回Predicate
Predicate predicate = cb.and(p1, p2);
return predicate;
}
};
List<Customer> list = dao.findAll(spe);
for (Customer customer : list) {
System.out.println(customer);
}
}
/**
* 使用JpaSpecificationExecutor的findAll,查询所有并根据id降序、cust_name升序
* 使用Sort对象的构造方法传入排序类型和属性名称
* 多个排序使用Sort对象的and方法连接
*/
@Test
public void findAllTest3()
{
// select * from sustomer order by id desc, cust_name asc
Sort sort1 = new Sort(Sort.Direction.DESC, "id");
Sort sort2 = new Sort(Sort.Direction.ASC, "custName");
Sort and = sort1.and(sort2);
List<Customer> list = dao.findAll(and);
for (Customer customer : list) {
System.out.println(customer);
}
}
/**
* 使用JpaSpecificationExecutor的findAll,查询所有custAddress等于"西游记"的客户,并分页
*/
@Test
public void findAllTest4()
{
Specification<Customer> spe = new Specification<Customer>() {
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
Path<Object> custAddress = root.get("custAddress");
Predicate predicate = cb.equal(custAddress, "西游记");
return predicate;
}
};
Pageable pageable = new PageRequest(0, 2);
Page<Customer> page = dao.findAll(spe, pageable);
// 获取查询出来的数据主体
List<Customer> content = page.getContent();
for (Customer customer : content) {
System.out.println(customer);
}
// 获取符合条件的总条数
long totalCount = page.getTotalElements();
System.out.println("符合条件的总条数" + totalCount);
// 获取符合条件的总页数
int totalPages = page.getTotalPages();
System.out.println("符合条件的总页数" + totalPages);
}
/**
* 查询custAddress等于"西游记"的客户数量
*/
@Test
public void countTest()
{
Specification<Customer> spe = new Specification<Customer>() {
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
Path<Object> custAddress = root.get("custAddress");
Predicate predicate = cb.equal(custAddress, "西游记");
return predicate;
}
};
// 传入条件,获取结果
long count = dao.count(spe);
System.out.println(count);
}
}