最近接触到的项目要使用Spring Data JPA 的动态查询。学习了几天之后,以一个Student的小例子做一下总结。
1.定义StudentFilter,查询条件的集合,即通过ID和name来查询Student。
@Data
public class StudentFilter {
private String id;
private String name;
}
2.定义一个类StudentSpecs,查询方法的集合
public class StudentSpecs {
//方法1。Specification:规格,规范。Predicate:断言。将复杂的查询提取成一个方法。
public static Specification getStudentByFilter(StudentFilter StudentFilter){
return new Specification() {//使用 Specification 的匿名内部类
@Override
/**
* @param *root: 代表查询的实体类.
* @param query: 可以从中可到 Root 对象, 即告知 JPA Criteria 查询要查询哪一个实体类.
* @param *cb: CriteriaBuilder 对象. 用于创建 Criteria 相关对象的工厂
* @return: *Predicate 类型, 代表一个查询条件.
*/
public Predicate toPredicate(Root root, CriteriaQuery> criteriaQuery, CriteriaBuilder criteriaBuilder) {
List predicates = new ArrayList();//将多个查询条件放在一个list中
if(StudentFilter.getId() != null && !"".equals(StudentFilter.getId())){
predicates.add(criteriaBuilder.equal(root.get("id"), StudentFilter.getId()));
}
if(StudentFilter.getName() != null && !"".equals(StudentFilter.getName())){
predicates.add(criteriaBuilder.equal(root.get("name"), StudentFilter.getName()));
}
//criteriaBuilder.and()返回一个predicate对象
return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
}
};
}
//还可以继续添加方法2
}
其中,criteriaBuilder.equal方法返回一个predicate对象,加入predicates list中,拆开写就是
String id = root.get("id");
Predicate predicateId = criteriaBuilder.equal(id, StudentFilter.getId());//equal表示过滤条件是相等
predicates.add(predicateId);
3.有一个类的Repository,继承JPA的JpaSpecificationExecutor
public interface StudentRepository extends DataRepository, JpaSpecificationExecutor {
}
4.Manager层,实例化一个Repository,然后定义查询方法,去调用repository的findAll方法,将之前Specification中的查询方法添加进去。这样的话,再有别的查询需求时,直接放到Specs里,然后repository的findAll中加入即可,可以与之前的查询方法and或者or
public class StudentManager {
StudentRepository StudentRepository;
public List getStudentByFilter(StudentFilter StudentFilter) {
return StudentRepository.findAll(StudentSpecs.getStudentByFilter(StudentFilter));
}
}
5.Service层。这样写有个不好处是参数多的话会比较麻烦。后续看看怎么传递对象。
@GET
@Path("/student")
List getStudentsByFilter(@QueryParam("id") String id,@QueryParam("name") String name);
6.Service Implement层。将从service层穿过来的参数赋值给对象,供查询方法调用
public List getStudentssByFilter(String id, String name,) {
StudentFilter StudentFilter = new StudentFilter();
StudentFilter.setId(id);
return StudentManager.getStudentByFilter(StudentFilter);
}
7.test。先post两个学生实例,再进行查询,支持空状态查询。
@Test
public void testStudentGetMethod(){
Student Student = new Student();
Student.setId("1");
Student.setName("1");
Student Student1 = new Student();
Student1.setId("2");
Student1.setName("1");
StudentService.post(Student);
StudentService.post(Student1);
Assert.assertEquals(2, StudentService.getStudentsByFilter("","",).size());
}