大家好,欢迎来到IT知识分享网。
在日常工作中,Spring Data JPA的使用给我们带来了极大的方便,但是实际业务中很多场景需要支持动态查询。比如前端查询功能提供了很多查询条件,用户可以根据一部分条件进行查询,那么后端就需要支持可配置的查询服务。在使用mybatis等时,可以用动态查询的方式轻松搞定,但是对于初次使用Spring Data JPA的小白来说,着实有些困难。本人也是在实际工作中参考资料,一步步摸索,掌握了一定的方法,现跟大家分享。
通过了解发现,Spring Data JPA是支持动态查询的,需要我们的repo继承JpaSpecificationExecutor接口,使用的时候传入相应参数即可。先看一下JpaSpecificationExecutor接口:
public interface JpaSpecificationExecutor<T> {
T findOne(Specification<T> spec);
List<T> findAll(Specification<T> spec);
Page<T> findAll(Specification<T> spec, Pageable pageable);
List<T> findAll(Specification<T> spec, Sort sort);
long count(Specification<T> spec);
}
其中,Pageable是分页查询用的,Sort是排序用的,比较简单,先不做介绍,本次主要介绍Specification。先看看它的定义:
public interface Specification<T> {
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
}
Root是查询的根对象,CriteriaBuilder可以用来构建查询关系。下面以一个实例来介绍具体使用:
下面是一个保存学生信息的表t_student:
先构建一下查询条件的参数体:
public class StudentParam {
private String name; //姓名
private String address; //住址
private String school; //学校
private String birthday; //出生日期
//省略get、set方法。
}
查询条件包含姓名、住址、学校、出生日期等。
看一下repo接口:
public interface StudentRepo extends CrudRepository<StudentEntity, String>, JpaSpecificationExecutor,
PagingAndSortingRepository<StudentEntity, String> {
}
业务实现代码:
public List<Student> queryStudent(final StudentParam studentParam) {
Specification<StudentEntity> specification = new Specification<StudentEntity>() {
public Predicate toPredicate(Root<StudentEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> predicates = new ArrayList<Predicate>();
if (studentParam.getName() != null && !"".equals(studentParam.getName())) {
predicates.add(cb.equal(root.<String>get("name"), studentParam.getName()));
}
if (studentParam.getStartDate() != null && !"".equals(studentParam.getStartDate())) {
predicates.add(cb.greaterThan(root.<String>get("birthday"), studentParam.getStartDate()));
}
if (studentParam.getEndDate() != null && !"".equals(studentParam.getEndDate())) {
predicates.add(cb.lessThan(root.<String>get("birthday"), studentParam.getEndDate()));
}
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
}
};
List<StudentEntity> studentEntities = studentRepo.findAll(specification);
List<Student> students = new ArrayList<Student>();
for (StudentEntity studentEntity : studentEntities) {
students.add(studentCopier.copy(studentEntity));
}
return students;
}
说明:以其中一行代码:predicates.add(cb.equal(root.<String>get(“name”), studentParam.getName()));为例。”name”指定了实体的其中一个属性,studentParam.getName()是传入的姓名参数值,equal指的是等于。此段代码的含义是where条件,如:name=’张三’。注意指定的属性名必须与查询实体的属性名一致,否则会报错。
测试代码:
@Test
public void queryStudentTest() {
StudentParam studentParam = new StudentParam();
studentParam.setName("张三");
studentParam.setStartDate("2001-03-01");
studentParam.setEndDate("2002-03-01");
List<Student> students = studentService.queryStudent(studentParam);
for (Student student : students) {
info(student.toString());
}
}
执行结果:
Hibernate:
select
studentent0_.id as id1_0_,
studentent0_.address as address2_0_,
studentent0_.birthday as birthday3_0_,
studentent0_.name as name4_0_,
studentent0_.school as school5_0_,
studentent0_.tel as tel6_0_
from
t_student studentent0_
where
studentent0_.name=?
and studentent0_.birthday>?
and studentent0_.birthday<?
Student{id='b6ef1f42e8a64367abc251af22246870', name='张三', address='菜市场', tel='12314512312311', school='西城中学', birthday='2001-03-11'}
Student{id='bc56bad3fd4e4604abe8a1c4ee2c1f66', name='张三', address='菜市场', tel='12314512312311', school='明湖中学', birthday='2002-02-11'}
Student{id='ffe6c2942c574d118fcfc4836580791d', name='张三', address='菜市场', tel='12314512312311', school='实验中学', birthday='2002-01-11'}
在执行中,我们发现Spring Data JPA根据配置的查询条件自动生成了条件语句:where
studentent0_.name=?
and studentent0_.birthday>?
and studentent0_.birthday<?
上例中,将查询条件通过and关联起来,进一步,如果我们需要用的or,该如何实现?看下面:
public List<Student> queryStudent(final StudentParam studentParam) {
Specification<StudentEntity> specification = new Specification<StudentEntity>() {
public Predicate toPredicate(Root<StudentEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> predicates = new ArrayList<Predicate>();
if (studentParam.getName() != null && !"".equals(studentParam.getName())) {
predicates.add(cb.equal(root.<String>get("name"), studentParam.getName()));
}
if (studentParam.getStartDate() != null && !"".equals(studentParam.getStartDate())) {
predicates.add(cb.greaterThan(root.<String>get("birthday"), studentParam.getStartDate()));
}
if (studentParam.getEndDate() != null && !"".equals(studentParam.getEndDate())) {
predicates.add(cb.lessThan(root.<String>get("birthday"), studentParam.getEndDate()));
}
//定义or的条件数组
List<Predicate> orPredicates = new ArrayList<Predicate>();
if (studentParam.getSchool() != null && !"".equals(studentParam.getSchool())) {
orPredicates.add(cb.equal(root.<String>get("school"), studentParam.getSchool()));
}
if (studentParam.getAddress() != null && !"".equals(studentParam.getAddress())) {
orPredicates.add(cb.equal(root.<String>get("address"), studentParam.getAddress()));
}
//生成or的查询表达式
Predicate orPredicate = cb.or(orPredicates.toArray(new Predicate[orPredicates.size()]));
//与and结合起来
predicates.add(orPredicate);
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
}
};
List<StudentEntity> studentEntities = studentRepo.findAll(specification);
List<Student> students = new ArrayList<Student>();
for (StudentEntity studentEntity : studentEntities) {
students.add(studentCopier.copy(studentEntity));
}
return students;
}
测试代码:
@Test
public void queryStudentTest() {
StudentParam studentParam = new StudentParam();
studentParam.setName("张三");
studentParam.setStartDate("2001-03-01");
studentParam.setEndDate("2002-03-01");
studentParam.setAddress("清江小区");
studentParam.setSchool("西城中学");
List<Student> students = studentService.queryStudent(studentParam);
for (Student student : students) {
info(student.toString());
}
}
执行结果:
Hibernate:
select
studentent0_.id as id1_0_,
studentent0_.address as address2_0_,
studentent0_.birthday as birthday3_0_,
studentent0_.name as name4_0_,
studentent0_.school as school5_0_,
studentent0_.tel as tel6_0_
from
t_student studentent0_
where
studentent0_.name=?
and studentent0_.birthday>?
and studentent0_.birthday<?
and (
studentent0_.school=?
or studentent0_.address=?
)
Student{id='b6ef1f42e8a64367abc251af22246870', name='张三', address='菜市场', tel='12314512312311', school='西城中学', birthday='2001-03-11'}
Spring Data JPA 支持的动态查询也非常强大,实际工作中可以根据情况灵活配置。希望我的分享能给需要的朋友一点帮助,不足之处,敬请斧正。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/10190.html