封装JpaSpecificationExecutor简化多条件查询
一、JpaSpecificationExecutor原生查询及其概述
1.1 概述
Spring Data JPA为我们提供了一系列的接口比如:Repository、CrudRepository、PagingAndSortingRepository、JpaRepository、JPASpecificationExecutor等。我们只需要继承这些接口就可以很方便的对数据库进行操作。但是当我们运用JPASpecificationExecutor接口进行一些比较复杂的条件查询的时候,就会显得有点麻烦,下面先来个查询的demo体验一下:
1.2 原生条件查询
我们假设usersRepositorySpecification已经继承了相关接口,以name和age为条件进行查询:
/**
* JpaSpecificationExecutor 多条件测试
*/
@Test
public void testJpaSpecificationExecutor2() {
/**
* Specification<Users>:用于封装查询条件
*/
Specification<Users> spec = new Specification<Users>() {
//Predicate:封装了 单个的查询条件
/**
* Root<Users> root:查询对象的属性的封装。
* CriteriaQuery<?> query:封装了我们要执行的查询中的各个部分的信息,select from order by
* CriteriaBuilder cb:查询条件的构造器。定义不同的查询条件
*/
@Override
public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> list = new ArrayList<>();
list.add(cb.equal(root.get("name"),"张三三"));
list.add(cb.equal(root.get("age"),20));
Predicate[] arr = new Predicate[list.size()];
return cb.and(list.toArray(arr));
}
};
List<Users> list = this.usersRepositorySpecification.findAll(spec);
for (Users users : list) {
System.out.println(users);
}
}
二、对上述查询进行封装简化
QueryWraper类,包装用于构建JPA动态查询时所需的对象
public class QueryWraper<T> {
public QueryWraper(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb, List<Predicate> predicates) {
this.root = root;
this.query = query;
this.cb = cb;
this.predicates = predicates;
}
/**
* JPA Root
*/
private Root<T> root;
/**
* JPA CriteriaBuilder
*/
private CriteriaBuilder cb;
/**
* JPA Predicate 集合
*/
private List<Predicate> predicates;
/**
* JPA 查询对象
*/
private CriteriaQuery<?> query;
/**
* <pre>
* 增加查询条件
* <pre>
* @param predicate
* @author jojo 2014-8-12 下午3
36
*/
public void addPredicate(Predicate predicate) {
this.predicates.add(predicate);
}
public Root<T> getRoot() {
return root;
}
public void setRoot(Root<T> root) {
this.root = root;
}
public CriteriaBuilder getCb() {
return cb;
}
public void setCb(CriteriaBuilder cb) {
this.cb = cb;
}
public List<Predicate> getPredicates() {
return predicates;
}
public void setPredicates(List<Predicate> predicates) {
this.predicates = predicates;
}
public CriteriaQuery<?> getQuery() {
return query;
}
public void setQuery(CriteriaQuery<?> query) {
this.query = query;
}
}
AbstractConditionBuilder抽象类,提供比如:in条件、between条件、like条件等一系列复杂查询条件
public abstract class AbstractConditionBuilder<T> {
/**
* 添加in条件
* @param queryWraper
* @param column 哪个属性
* @param values 在(in)哪些值里面
*/
protected void addInConditionToColumn(QueryWraper<T> queryWraper, String column, Object values) {
if (needAddCondition(values)) {
Path<?> fieldPath = getPath(queryWraper.getRoot(), column); //得到最终的路径
if(values.getClass().isArray()) {
queryWraper.addPredicate(fieldPath.in((Object[])values)); //in :创建Predicate以测试表达式是否为参数列表的成员,返回Predicate
}else if(values instanceof Collection) {
queryWraper.addPredicate(fieldPath.in((Collection<?>)values));
}
}
}
/**
* 添加between条件查询
* @param queryWraper
* @param experssion
* @param minValue 范围下限
* @param maxValue 范围上限
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
protected void addBetweenConditionToColumn(QueryWraper<T> queryWraper, String column, Comparable minValue, Comparable maxValue) {
if (minValue != null || maxValue != null) {
Path<? extends Comparable> fieldPath = getPath(queryWraper.getRoot(), column);
if(minValue != null && maxValue != null){
queryWraper.addPredicate(queryWraper.getCb().between(fieldPath, minValue, processMaxValueOnDate(maxValue)));
}else if(minValue != null){
queryWraper.addPredicate(queryWraper.getCb().greaterThanOrEqualTo(fieldPath, minValue));
}else if(maxValue != null){
queryWraper.addPredicate(queryWraper.getCb().lessThanOrEqualTo(fieldPath, processMaxValueOnDate(maxValue)));
}
}
}
/**
* 当范围查询的条件是小于,并且值的类型是Date时,将传入的Date值变为当天的夜里12点的值。
* @param maxValue
* @return
* @author zhailiang
* @since 2016年12月14日
*/
@SuppressWarnings("rawtypes")
private Comparable processMaxValueOnDate(Comparable maxValue) {
if(maxValue instanceof Date) {
maxValue = new DateTime(maxValue).withTimeAtStartOfDay().plusDays(1).plusSeconds(-1).toDate();
}
return maxValue;
}
/**
* 添加大于条件查询
* @param queryWraper
* @param experssion
* @param minValue
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
protected void addGreaterThanConditionToColumn(QueryWraper<T> queryWraper, String column, Comparable minValue) {
if (minValue != null) {
Path<? extends Comparable> fieldPath = getPath(queryWraper.getRoot(), column);
queryWraper.addPredicate(queryWraper.getCb().greaterThan(fieldPath, minValue));
}
}
/**
* 添加大于等于条件查询
* @param queryWraper
* @param experssion
* @param minValue
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
protected void addGreaterThanOrEqualConditionToColumn(QueryWraper<T> queryWraper, String column, Comparable minValue) {
if (minValue != null) {
Path<? extends Comparable> fieldPath = getPath(queryWraper.getRoot(), column);
queryWraper.addPredicate(queryWraper.getCb().greaterThanOrEqualTo(fieldPath, minValue));
}
}
/**
* 添加小于条件查询
* @param queryWraper
* @param experssion
* @param maxValue
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
protected void addLessThanConditionToColumn(QueryWraper<T> queryWraper, String column, Comparable maxValue) {
if (maxValue != null) {
Path<? extends Comparable> fieldPath = getPath(queryWraper.getRoot(), column);
queryWraper.addPredicate(queryWraper.getCb().lessThan(fieldPath, processMaxValueOnDate(maxValue)));
}
}
/**
* 添加小于等于条件查询
* @param queryWraper
* @param experssion
* @param maxValue
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
protected void addLessThanOrEqualConditionToColumn(QueryWraper<T> queryWraper, String column, Comparable maxValue) {
if (maxValue != null) {
Path<? extends Comparable> fieldPath = getPath(queryWraper.getRoot(), column);
queryWraper.addPredicate(queryWraper.getCb().lessThanOrEqualTo(fieldPath, processMaxValueOnDate(maxValue)));
}
}
/**
* <pre>
* 添加like条件
* <pre>
* @param queryWraper
* @param column 指出要向哪个字段添加包含(like)条件
* @param value like什么
* @author jojo 2014-8-12 下午3
44
*/
protected void addLikeConditionToColumn(QueryWraper<T> queryWraper, String column, String value) {
if (StringUtils.isNotBlank(value)) {
queryWraper.addPredicate(createLikeCondition(queryWraper, column, value));
}
}
/**
* @param queryWraper
* @param column 查哪个字段
* @param value 字段like什么
* @return
* @author zhailiang
* @since 2016年12月13日
*/
@SuppressWarnings("unchecked")
protected Predicate createLikeCondition(QueryWraper<T> queryWraper, String column, String value) {
Path<String> fieldPath = getPath(queryWraper.getRoot(), column);
Predicate condition = queryWraper.getCb().like(fieldPath, "%" + value + "%");
return condition;
}
/**
* <pre>
* 添加like条件
* <pre>
* @param queryWraper
* @param column
* @param value
* @author jojo 2014-8-12 下午3
44
*/
@SuppressWarnings("unchecked")
protected void addStartsWidthConditionToColumn(QueryWraper<T> queryWraper, String column, String value) {
if (StringUtils.isNotBlank(value)) {
Path<String> fieldPath = getPath(queryWraper.getRoot(), column);
queryWraper.addPredicate(queryWraper.getCb().like(fieldPath, value + "%"));
}
}
/**
* 添加等于条件
* @param queryWraper
* @param column 指出要向哪个字段添加条件
* @param value 指定字段的值
*/
protected void addEqualsConditionToColumn(QueryWraper<T> queryWraper, String column, Object value) {
if(needAddCondition(value)) {
Path<?> fieldPath = getPath(queryWraper.getRoot(), column);
queryWraper.addPredicate(queryWraper.getCb().equal(fieldPath, value));
}
}
/**
* 添加不等于条件
* @param queryWraper
* @param column 指出要向哪个字段添加条件
* @param value 指定字段的值
*/
protected void addNotEqualsConditionToColumn(QueryWraper<T> queryWraper, String column, Object value) {
if(needAddCondition(value)) {
Path<?> fieldPath = getPath(queryWraper.getRoot(), column);
queryWraper.addPredicate(queryWraper.getCb().notEqual(fieldPath, value));
}
}
/**
* <pre>
*
* <pre> 得到属性的路径
* @param root
* @param property
* @return
* @author jojo 2014-8-12 下午3:06:58
*/
@SuppressWarnings("rawtypes")
protected Path getPath(Root root, String property){
//Path代表一个简单或者复杂的属性路径
String[] names = StringUtils.split(property, "."); //比如路径是admin.role.resource,需要为resource创建path
Path path = root.get(names[0]);
for (int i = 1; i < names.length; i++) {
path = path.get(names[i]); //创建与引用属性相对应的路径
}
return path;
}
/**
* <pre>
* 判断是否需要添加where条件
* <pre>
* @param value
* @return
* @author jojo 2014-8-12 下午3:07:00
*/
@SuppressWarnings("rawtypes")
protected boolean needAddCondition(Object value) {
boolean addCondition = false;
if (value != null) {
if(value instanceof String) {
if(StringUtils.isNotBlank(value.toString())) {
addCondition = true;
}
}else if(value.getClass().isArray()) {
if(ArrayUtils.isNotEmpty((Object[]) value)) {
addCondition = true;
}
}else if(value instanceof Collection) {
if(CollectionUtils.isNotEmpty((Collection) value)) {
addCondition = true;
}
}else {
addCondition = true;
}
}
return addCondition;
}
}
AbstractEventConditionBuilder抽象类,继承AbstractConditionBuilder类,根据传上来的条件对象,对AbstractConditionBuilder查询方法进行进一步封装。
public abstract class AbstractEventConditionBuilder<T, C> extends AbstractConditionBuilder<T> {
/**
* 查询条件
*/
private C condition;
/**
* @param condition 查询条件
*/
public AbstractEventConditionBuilder(C condition){
this.condition = condition;
}
/**
* 向查询中添加包含(like)条件
*
* @param queryWraper
* @param field 指出查询条件的值从condition对象的哪个字段里取,并且指出要向哪个字段添加包含(like)条件。(同一个字段名称)
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalAccessException
*/
protected void addLikeCondition(QueryWraper<T> queryWraper, String field){
addLikeCondition(queryWraper, field, field);
}
/**
* 向查询中添加包含(like)条件
*
* @param queryWraper
* @param field 指出查询条件的值从condition对象的哪个字段里取
* @param column 指出要向哪个字段添加包含(like)条件
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalAccessException
*/
protected void addLikeCondition(QueryWraper<T> queryWraper, String field, String column){
addLikeConditionToColumn(queryWraper, column, (String)
getValue(getCondition(), field)); //得到condition里面 field字段的值
}
/**
* 向查询中添加包含(like)条件,%放在值后面
*
* @param queryWraper
* @param field 指出查询条件的值从condition对象的哪个字段里取,并且指出要向哪个字段添加包含(like)条件。(同一个字段名称)
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalAccessException
*/
protected void addStartsWidthCondition(QueryWraper<T> queryWraper, String field){
addStartsWidthCondition(queryWraper, field, field);
}
/**
* 向查询中添加包含(like)条件,%放在值后面
*
* @param queryWraper
* @param field 指出查询条件的值从condition对象的哪个字段里取
* @param column 指出要向哪个字段添加包含(like)条件
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalAccessException
*/
protected void addStartsWidthCondition(QueryWraper<T> queryWraper, String field, String column){
addStartsWidthConditionToColumn(queryWraper, column, (String)
getValue(getCondition(), field));
}
/**
* 向查询中添加等于(=)条件
*
* @param queryWraper
* @param field 指出查询条件的值从condition对象的哪个字段里取,并且指出要向哪个字段添加条件。(同一个字段名称)
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalAccessException
*/
protected void addEqualsCondition(QueryWraper<T> queryWraper, String field){
addEqualsCondition(queryWraper, field, field);
}
/**
* 向查询中添加等于(=)条件
*
* @param queryWraper
* @param field 指出查询条件的值从condition对象的哪个字段里取
* @param column 指出要向哪个字段添加条件
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalAccessException
*/
protected void addEqualsCondition(QueryWraper<T> queryWraper, String field, String column){
addEqualsConditionToColumn(queryWraper, column,
getValue(getCondition(), field));
}
/**
* 向查询中添加不等于(!=)条件
*
* @param queryWraper
* @param field 指出查询条件的值从condition对象的哪个字段里取,并且指出要向哪个字段添加条件。(同一个字段名称)
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalAccessException
*/
protected void addNotEqualsCondition(QueryWraper<T> queryWraper, String field){
addNotEqualsCondition(queryWraper, field, field);
}
/**
* 向查询中添加等于(=)条件
*
* @param queryWraper
* @param field 指出查询条件的值从condition对象的哪个字段里取
* @param column 指出要向哪个字段添加条件
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalAccessException
*/
protected void addNotEqualsCondition(QueryWraper<T> queryWraper, String field, String column){
addNotEqualsConditionToColumn(queryWraper, column, getValue(getCondition(), field));
}
/**
* <pre>
* 向查询中添加in条件
* <pre>
* @param queryWraper
* @param field
* @author jojo 2014-8-12 下午3:26:50
*/
protected void addInCondition(QueryWraper<T> queryWraper, String field) {
addInCondition(queryWraper, field, field);
}
/**
* <pre>
* 向查询中添加in条件
* <pre>
* @param queryWraper
* @param field
* @param column
* @author jojo 2014-8-12 下午3:27:46
*/
protected void addInCondition(QueryWraper<T> queryWraper, String field, String column) {
addInConditionToColumn(queryWraper, column,
getValue(getCondition(), field));
}
/**
* <pre>
* 向查询中添加between条件
* <pre>
* @param queryWraper
* @param field
* @author jojo 2014-8-12 下午3:26:50
*/
protected void addBetweenCondition(QueryWraper<T> queryWraper, String field) {
addBetweenCondition(queryWraper, field, field+"To", field);
}
/**
* <pre>
* 向查询中添加between条件
* <pre>
* @param queryWraper
* @param field
* @param column
* @author jojo 2014-8-12 下午3:27:46
*/
@SuppressWarnings("rawtypes")
protected void addBetweenCondition(QueryWraper<T> queryWraper, String startField, String endField, String column) {
addBetweenConditionToColumn(queryWraper, column,
(Comparable)getValue(getCondition(), startField),
(Comparable)getValue(getCondition(), endField));
}
/**
* <pre>
* 向查询中添加大于条件
* <pre>
* @param queryWraper
* @param field
* @author jojo 2014-8-12 下午3:26:50
*/
protected void addGreaterThanCondition(QueryWraper<T> queryWraper, String field) {
addGreaterThanCondition(queryWraper, field, field);
}
/**
* <pre>
* 向查询中添加大于条件
* <pre>
* @param queryWraper
* @param field
* @param column
* @author jojo 2014-8-12 下午3:27:46
*/
@SuppressWarnings("rawtypes")
protected void addGreaterThanCondition(QueryWraper<T> queryWraper, String field, String column) {
addGreaterThanConditionToColumn(queryWraper, column,
(Comparable)getValue(getCondition(), field));
}
/**
* <pre>
* 向查询中添加大于等于条件
* <pre>
* @param queryWraper
* @param field
* @author jojo 2014-8-12 下午3:26:50
*/
protected void addGreaterThanOrEqualCondition(QueryWraper<T> queryWraper, String field) {
addGreaterThanOrEqualCondition(queryWraper, field, field);
}
/**
* <pre>
* 向查询中添加大于等于条件
* <pre>
* @param queryWraper
* @param field
* @param column
* @author jojo 2014-8-12 下午3:27:46
*/
@SuppressWarnings("rawtypes")
protected void addGreaterThanOrEqualCondition(QueryWraper<T> queryWraper, String field, String column) {
addGreaterThanOrEqualConditionToColumn(queryWraper, column,
(Comparable)getValue(getCondition(), field));
}
/**
* <pre>
* 向查询中添加小于条件
* <pre>
* @param queryWraper
* @param field
* @author jojo 2014-8-12 下午3:26:50
*/
protected void addLessThanCondition(QueryWraper<T> queryWraper, String field) {
addLessThanCondition(queryWraper, field, field);
}
/**
* <pre>
* 向查询中添加小于条件
* <pre>
* @param queryWraper
* @param field
* @param column
* @author jojo 2014-8-12 下午3:27:46
*/
@SuppressWarnings("rawtypes")
protected void addLessThanCondition(QueryWraper<T> queryWraper, String field, String column) {
addLessThanConditionToColumn(queryWraper, column,
(Comparable)getValue(getCondition(), field));
}
/**
* <pre>
* 向查询中添加小于等于条件
* <pre>
* @param queryWraper
* @param field
* @author jojo 2014-8-12 下午3:26:50
*/
protected void addLessThanOrEqualCondition(QueryWraper<T> queryWraper, String field) {
addLessThanOrEqualCondition(queryWraper, field, field);
}
/**
* <pre>
* 向查询中添加小于等于条件
* <pre>
* @param queryWraper
* @param field
* @param column
* @author jojo 2014-8-12 下午3:27:46
*/
@SuppressWarnings("rawtypes")
protected void addLessThanOrEqualCondition(QueryWraper<T> queryWraper, String field, String column) {
addLessThanOrEqualConditionToColumn(queryWraper, column,
(Comparable)getValue(getCondition(), field));
}
/**
*
* @param condition 从这个对象里面查
* @param field 要查询的属性
* @return
*/
private Object getValue(C condition, String field) {
try {
//得到condition对象中field属性的值
//使用示例:getProperty(book,"authors[0].favorites(food)")
return PropertyUtils.getProperty(condition, field);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
/**
* @return the condition
*/
public C getCondition() {
return condition;
}
/**
* @param condition the condition to set
*/
public void setCondition(C condition) {
this.condition = condition;
}
}
MyImoocSpecification类,继承AbstractEventConditionBuilder类,并实现Specification接口,重写toPredicate()方法,使用时继承该类即可
public abstract class MySpecification<T, C> extends AbstractEventConditionBuilder<T, C> implements Specification<T> {
//AbstractEventConditionBuilder里面封装了添加各种查询条件的方法
/**
* @param condition
*/
public MySpecification(C condition) {
super(condition);
}
/**
*
* 构建查询条件,子类必须实现addCondition方法来编写查询的逻辑。
*
* 子类可以通过addFetch方法控制查询的关联和抓取行为。
*
*/
@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
if (Long.class != query.getResultType()) {
addFetch(root);
}
List<Predicate> predicates = new ArrayList<Predicate>();
QueryWraper<T> queryWraper = new QueryWraper<T>(root, query, cb, predicates);
addCondition(queryWraper);
Predicate permissionCondition = getPermissionCondition(queryWraper);
if (permissionCondition != null) {
queryWraper.addPredicate(permissionCondition);
}
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
}
/**
* 添加权限条件,如果要查询的domain实现了{@link ManagedByOrgan}接口,那么传入的Condition对象也应该实现
* {@link ManagedByOrgan}接口,
* 程序会尝试从Condition对象获取organFullId,然后作为like查询条件添加到查询中。
* 查出所有以传入的organFullId开头的domain.
*
* @param queryWraper
* @return
*/
protected Predicate getPermissionCondition(QueryWraper<T> queryWraper) {
return null;
}
/**
* <pre>
* 子类可以通过覆盖此方法实现关联抓取,避免n+1查询
*
* <pre>
*
* @param root
* @author jojo 2014-7-22 上午9
26
*/
protected void addFetch(Root<T> root) {
}
protected abstract void addCondition(QueryWraper<T> queryWraper); //钩子方法,子类实现 自动调用
}
三、使用示例
3.1 创建条件封装对象
public class AdminCondition {
private String username;
/**
* @return the username
*/
public String getUsername() {
return username;
}
/**
* @param username the username to set
*/
public void setUsername(String username) {
this.username = username;
}
}
3.2 继承MySpecification类
传入条件封装对象,以及结果实体类型
public class AdminSpec extends ImoocSpecification<Admin, AdminCondition> {
public AdminSpec(AdminCondition condition) {
super(condition);
}
@Override
protected void addCondition(QueryWraper<Admin> queryWraper) {
addLikeCondition(queryWraper, "username");
}
}
3.3 调用
public class AdminServiceImpl implements AdminService {
@Autowired
private AdminRepository adminRepository;
public Page<AdminInfo> query(AdminCondition condition, Pageable pageable) {
Page<Admin> admins = adminRepository.findAll(new AdminSpec(condition), pageable);
return QueryResultConverter.convert(admins, AdminInfo.class, pageable);
}
}
还没有评论,来说两句吧...