1. 背景
接触了一个新项目,项目使用的框架为Spring-data-jpa,起初对这个项目还是挺感兴趣的,啊毕竟之前一直用Mybatis-Plus框架,深陷mp框架毒害啊(注:不喜欢写sql)。
然后就看到了类似于以下的代码:
/**
* 实体类
*/
@Entity
public class User{
private Long id;
private String nickname;
private String gender;
}
// 方法实现
@Repository
public class UserDaoImpl implements UserDao{
@PersistenceContext
private EntityManager em;
public List<User> loadByNicknameAndGender(){
String hql = "select * from User where 1=1 ";
if(StringUtil.isNotBlank(a)){
hql += " and nickname = '"+a+"'";
}
if(StringUtil.isNotBlank(b)){
hql += " and gender = '"+b+"'";
}
return this.em.createQuery(hql).getResultList();
}
}
当时我就懵了,这什么玩意,这是面对sql开发吗?这一个Dao层得写多少代码才行啊,效率啊,我要的是效率啊魂淡!!要不是项目重构复杂度过大,我差点就打算直接重构Mybatis-Plus了,代码清爽整洁不香吗。于是便有了以下改造(copy + 修正)之路
2. 了解JPA的Criteria API查询
- 根据官方的文档,咱们可以这样改成这样
1. 首先我们创建一个Repository对象
/**
* UserRepository对象
*/
public interface UserRepository extends JpaRepository<User, String> , JpaSpecificationExecutor<User> {
}
2. 然后修改UserDaoImpl的方法
public List<User> loadByNicknameAndGender(String a,String b){
QueryBuilder queryBuilder = em.getQueryBuilder();
CriteriaQuery< User> criteriaQuery = queryBuilder.createQuery(User.class);
Root<User> root = criteriaQuery.from(User.class);
List<Predicate> Predicates = new ArrayList<>();
if(StringUtil.isNotBlank(a)){
Predicate condition = queryBuilder.equal(root.get("nickname"), a);
Predicates.add(condition);
}
if(StringUtil.isNotBlank(b)){
Predicate condition = queryBuilder.equal(root.get("gender"),b);
Predicates.add(condition );
}
if(criterionList.isEmpty()){
return criterionList.add(builder.conjunction());
}
criteriaQuery.where(condition.toArray());
TypedQuery< User> typedQuery = em.createQuery(criteriaQuery);
return typedQuery.getResultList();
}
这样代码似乎变得没那么乱糟糟的, 至少少写了很多String的拼接,代码整体是整洁了不少。但是!!查询条件越多,这个方法依然会充斥着大量的判断和添加。而且我们还无法保证后期实体类字段可能出现变更带来的bug!
从上面这段代码中,我们可以分析发现,这个方法的执行顺序如下
1. 通过EntityManager 创建了一个QueryBuilder实例
2. 然后通过QueryBuilder 工厂构造一个 CriteriaQuery 实例,并给他赋值了泛型的声明,表明本次查询的具体返回对象,这里可以设置成其他的查询持久化对象
3. 随后CriteriaQuery表明本次查询通过哪个持久化对象进行本次的查询表,返回Root
4. 通过root.get("实体类字段")获取实体类的查询Path,然后通过queryBuilder来设置查询条件表达式,返回了一个Predicate的具体条件对象
通过这样的分析,我们可以提取其中的部分重复代码,将其封装成公共的工具类(让我们把这些代码藏起来hhh)!
3. 实现
1. 创建一个条件表达式的接口
public interface Criterion {
// 这里是一些常见操作的枚举
enum Operator {
EQ, NE, LIKE,LEFT_LIKE,RIGHT_LIKE, GT, LT, GTE, LTE, AND, OR, IN, NOTIN, ISNULL, IS_NOTNULL, ORDER_BY_DESC, ORDER_BY_ASC, IS_EMPTY, IS_NOT_EMPTY
}
/**
* 条件
*/
Predicate toPredicate(Root<?> root, CriteriaQuery<?> query,
CriteriaBuilder builder);
/**
* 排序表达式
*/
Order toOrder(Root<?> root,CriteriaQuery<?> query,CriteriaBuilder builder);
}
2. 创建一个查询容器,并实现了官方的Specification接口
/**
* @description 查询容器,实现了官方的Specification,并在此基础上做出改良
* @example
* 在DaoImpl中编写方法
* Criteria<T> criteria = new Criteria<T>().eq(T::getId(),1).in(T::getState(),Arrays.asList(1,2,3))...;
* this.findAll(criteria);
*
* @warn 该工具使用不适用于对象构造以及多级关联构造使用,暂时未加入参数属性检查和参数是否存在的检查,使用该工具请自行检查参数类型是否和目标属性一直
* Error: this.eq(Order::getMember,new Member()) 不推荐这样使用对象作为查询,会为查询带来额外的负担,建议使用 this.eq("member.id",id)
* Error: this.eq(Order::getMember::getId,1) 错误 正确应该为 this.eq("member.id",1) ,目前此方式查询支持多级关联 this.eq("member.xx.xx.id",1)
*/
public class Criteria<T> implements Specification<T> {
// 条件表达式列表
private final List<Criterion> criterionList = new ArrayList<>();
// 排序表达式列表
private final List<Criterion> orderList = new ArrayList<>();
/**
* 函数式接口
*
* @param <T>
* @param <R>
*/
@FunctionalInterface
public interface SFunction<T, R> extends Function<T, R>, Serializable {
}
/**
* 获取lambda表达式字段名称
*
* @param fn lambda表达式
* @param <T> 泛型
* @return 泛型对象的字段名
*/
public static <T> String getFieldName(SFunction<T, ?> fn) {
SerializedLambda serializedLambda = getSerializedLambda(fn);
// 从lambda信息取出method、field、class等
String fieldName = serializedLambda.getImplMethodName().substring("get".length());
fieldName = fieldName.replaceFirst(fieldName.charAt(0) + "", (fieldName.charAt(0) + "").toLowerCase());
return fieldName.replaceAll("[A-Z]", "$0");
}
/**
* 检查字段是否存在某个类中
* @param c 类
* @param fieldName 字段
* @return 是否存在
*/
public static Boolean checkField(Class<?> c,String fieldName){
Field[] fields = c.getDeclaredFields();
for (Field f : fields) {
if (fieldName.equals(f.getName())) {
return Boolean.TRUE;
}
}
return Boolean.FALSE;
}
/**
* 获取lambda表达式的SerializedLambda对象
*
* @param fn lambda表达式
* @param <T> 泛型
* @return SerializedLambda 序列化的lambda对象
*/
private static <T> SerializedLambda getSerializedLambda(SFunction<T, ?> fn) {
// 从function取出序列化方法
Method writeReplaceMethod;
try {
writeReplaceMethod = fn.getClass().getDeclaredMethod("writeReplace");
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
// 从序列化方法取出序列化的lambda信息
writeReplaceMethod.setAccessible(true);
try {
return (SerializedLambda) writeReplaceMethod.invoke(fn);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
/**
* 条件参数转换器,实现了动态查询方法
*
* @description 重写Specification的动态参数拼接方法,将criterionList中所有收集的条件函数转换为jpa的Predicate对象,并使用builder组装所有参数对象
* @param root 查询的根对象,用于标识查询的实体类
* @param query 顶层查询对象,用于自定义查询
* @param builder 查询条件
* @return 最终查询条件对象,类似于hql语句
*/
@Override
public Predicate toPredicate(Root<T> root,
CriteriaQuery<?> query,
CriteriaBuilder builder) {
if (!criterionList.isEmpty()) {
// 将所有条件用 and 联合起来
Predicate and = builder.and(criterionList.stream()
.map(criterion -> criterion.toPredicate(root, query, builder))
.toArray(Predicate[]::new));
query.where(and);
List<Order> orders = this.orderList.stream().map(order -> order.toOrder(root, query, builder)).collect(Collectors.toList());
query.orderBy(orders);
return query.getRestriction();
}
return builder.conjunction();
}
/**
* 添加一个多条件查询
* 例子
* hql += and (xx=1 and xx like '%2%')
*this.eq(new Criteria<xx>().eq(xx,1).like(xx,2));
* @param criteria 条件
* @return 本体
*/
public Criteria<T> add(Criteria<T> criteria){
List<Criterion> criterionList = criteria.criterionList;
if (CollectionUtil.isEmpty(criterionList)){
return this;
}
this.criterionList.add(new ComplexExpression(criterionList,Criterion.Operator.AND));
return this;
}
/**
* 添加一个多条件查询
*
* @param condition 是否添加
* @param criteria 条件
* @return 本体
*/
public Criteria<T> and(Boolean condition, Criteria<T> criteria) {
if (condition){
return this.add(criteria);
}
return this;
}
/**
* 添加一个多条件查询
*
* @param condition 是否添加
* @param criteria 条件
* @return 本体
*/
public Criteria<T> add(Boolean condition, Criteria<T> criteria){
if (condition){
return this.add(criteria);
}
return this;
}
/**
* 添加一个多条件查询
* 例子
* hql += and (xx=1 or xx=2)
* this.eq(new Criteria<xx>().eq(xx,1).eq(xx,2));
* @param criteria 条件
* @return 本体
*/
public Criteria<T> or(Criteria<T> criteria){
List<Criterion> criterionList = criteria.criterionList;
if (CollectionUtil.isEmpty(criterionList)){
return this;
}
this.criterionList.add(new ComplexExpression(criterionList,Criterion.Operator.OR));
return this;
}
/**
* 添加一个多条件查询
*
* @param condition 是否添加
* @param criteria 条件
* @return 本体
*/
public Criteria<T> or(Boolean condition,Criteria<T> criteria){
if (condition){
return this.or(criteria);
}
return this;
}
/**
* 等于
* 例子:
* hql += "and id = 1"
* this.eq(xx::getId,1);
* @param field 实体类字段
* @param value 值
*/
public Criteria<T> eq(SFunction<T, ?> field, Object value) {
criterionList.add(new SimpleExpression(getFieldName(field), value, Criterion.Operator.EQ));
return this;
}
/**
* 等于
* 例子:
* hql += "and id = 1"
* this.eq("id",1);
* @param field 实体类字段
* @param value 值
*/
public Criteria<T> eq(String field, Object value) {
criterionList.add(new SimpleExpression(field, value, Criterion.Operator.EQ));
return this;
}
/**
* 如果 condition 条件判断通过,那么添加eq的方法
* @param field 实体类字段
* @param value 值
*/
public Criteria<T> eq(boolean condition, SFunction<T, ?> field, Object value) {
if (condition) {
this.eq(field, value);
}
return this;
}
/**
* 如果 condition 条件判断通过,那么添加eq的方法
* @param field 实体类字段
* @param value 值
*/
public Criteria<T> eq(boolean condition, String field, Object value) {
if (condition) {
this.eq(field, value);
}
return this;
}
/**
* like
* 例子:
* hql += "and id like '%1%'"
* this.like(xx::getId,1);
* @param field 实体类字段
* @param value 值
*/
public Criteria<T> like(SFunction<T, ?> field, Object value) {
criterionList.add(new SimpleExpression(getFieldName(field), value, Criterion.Operator.LIKE));
return this;
}
/**
* like
* 例子:
* hql += "and id like '%1%'"
* this.like("id",1);
* @param field 实体类字段
* @param value 值
*/
public Criteria<T> like(String field, Object value) {
criterionList.add(new SimpleExpression(field, value, Criterion.Operator.LIKE));
return this;
}
/**
* 左like
* 例子:
* hql += "and id like '%1'"
* this.like("id",1);
* @param field 实体类字段
* @param value 值
*/
public Criteria<T> leftLike(SFunction<T, ?> field, Object value) {
criterionList.add(new SimpleExpression(getFieldName(field), value, Criterion.Operator.LEFT_LIKE));
return this;
}
/**
* 右like
* 例子:
* hql += "and id like '1%'"
* this.like("id",1);
* @param field 实体类字段
* @param value 值
*/
public Criteria<T> rightLike(SFunction<T, ?> field, Object value) {
criterionList.add(new SimpleExpression(getFieldName(field), value, Criterion.Operator.RIGHT_LIKE));
return this;
}
/**
* 如果 condition 条件判断通过,那么添加like的方法
* @param field 实体类字段
* @param value 值
*/
public Criteria<T> like(boolean condition, SFunction<T, ?> field, Object value) {
if (condition) {
this.like(field, value);
}
return this;
}
/**
* 如果 condition 条件判断通过,那么添加like的方法
* @param field 实体类字段
* @param value 值
*/
public Criteria<T> like(boolean condition, String field, Object value) {
if (condition) {
this.like(field, value);
}
return this;
}
/**
* 等于
* 例子:
* hql += "and id <> 1"
* this.ne(xx::getId,1);
* @param field 实体类字段
* @param value 值
*/
public Criteria<T> ne(SFunction<T, ?> field, Object value) {
criterionList.add(new SimpleExpression(getFieldName(field), value, Criterion.Operator.NE));
return this;
}
/**
* 如果 condition 条件判断通过,那么添加ne的方法
* @param field 实体类字段
* @param value 值
*/
public Criteria<T> ne(boolean condition, SFunction<T, ?> field, Object value) {
if (condition) {
this.ne(field, value);
}
return this;
}
/**
* in查询
* 例子:
* hql写法 hql += "and id in ?"
* 构造器写法 this.in(xx::getId,Arrays.asList(1,2,3));
* @param field 实体类字段
* @param coll 数组对象 list、set
*/
public Criteria<T> in(SFunction<T, ?> field, Collection<?> coll) {
criterionList.add(new SimpleExpression(getFieldName(field), coll, Criterion.Operator.IN));
return this;
}
/**
* 如果 condition 条件判断通过,那么添加in的方法
* @param field 实体类字段
* @param value 值
*/
public Criteria<T> in(boolean condition, SFunction<T, ?> field, Collection<?> value) {
if (condition) {this.in(field, value);}
return this;
}
/**
* in查询
* 例子:
* hql写法 hql += "and id in ?"
* 构造器写法 this.in("id",Arrays.asList(1,2,3));
* @param field 实体类字段
* @param coll 数组对象 list、set
*/
public Criteria<T> in(String field, Collection<?> coll) {
criterionList.add(new SimpleExpression(field, coll, Criterion.Operator.IN));
return this;
}
/**
* 如果 condition 条件判断通过,那么添加in的方法
* @param field 实体类字段
* @param value 值
*/
public Criteria<T> in(boolean condition, String field, Collection<?> value) {
if (condition) {this.in(field, value);}
return this;
}
/**
* notIn查询
* 例子:
* hql写法 hql += "and id not in (1,2,3)"
* 构造器写法 this.notIn(xx::getId,Arrays.asList(1,2,3));
* @param field 实体类字段
* @param coll 数组对象 list、set
*/
public Criteria<T> notIn(SFunction<T, ?> field, Collection<?> coll) {
criterionList.add(new SimpleExpression(getFieldName(field), coll, Criterion.Operator.NOTIN));
return this;
}
/**
* 如果 condition 条件判断通过,那么添加notIn的方法
* @param field 实体类字段
* @param value 值
*/
public Criteria<T> notIn(boolean condition, SFunction<T, ?> field, Collection<?> value) {
if (condition) {this.notIn(field, value);}
return this;
}
/**
* in查询
* 例子:
* hql写法 hql += "and id > 1"
* 构造器写法 this.gt(xx::getId,1);
* @param field 实体类字段
* @param value object对象
*/
public Criteria<T> gt(SFunction<T, ?> field, Object value) {
criterionList.add(new SimpleExpression(getFieldName(field), value, Criterion.Operator.GT));
return this;
}
/**
* 如果 condition 条件判断通过,那么加gt的方法
* @param field 实体类字段
* @param value 值
*/
public Criteria<T> gt(boolean condition, SFunction<T, ?> field, Object value) {
if (condition) {this.gt(field, value);}
return this;
}
/**
* in查询
* 例子:
* hql写法 hql += "and id >= 1"
* 构造器写法 this.gte(xx::getId,1);
* @param field 实体类字段
* @param value object对象
*/
public Criteria<T> gte(SFunction<T, ?> field, Object value) {
criterionList.add(new SimpleExpression(getFieldName(field), value, Criterion.Operator.GTE));
return this;
}
/**
* 如果 condition 条件判断通过,那么添加gte的方法
* @param field 实体类字段
* @param value 值
*/
public Criteria<T> gte(boolean condition, SFunction<T, ?> field, Object value) {
if (condition) {this.gte(field, value);}
return this;
}
/**
* in查询
* 例子:
* hql写法 hql += "and id < 1"
* 构造器写法 this.lt(xx::getId,1);
* @param field 实体类字段
* @param value object对象
*/
public Criteria<T> lt(SFunction<T, ?> field, Object value) {
criterionList.add(new SimpleExpression(getFieldName(field), value, Criterion.Operator.LT));
return this;
}
/**
* 如果 condition 条件判断通过,那么加lt的方法
* @param field 实体类字段
* @param value 值
*/
public Criteria<T> lt(boolean condition, SFunction<T, ?> field, Object value) {
if (condition) {this.lt(field, value);}
return this;
}
/**
* in查询
* 例子:
* hql写法 hql += "and id <= 1"
* 构造器写法 this.lte(xx::getId,1);
* @param field 实体类字段
* @param value object对象
*/
public Criteria<T> lte(SFunction<T, ?> field, Object value) {
criterionList.add(new SimpleExpression(getFieldName(field), value, Criterion.Operator.LTE));
return this;
}
/**
* 如果 condition 条件判断通过,那么添加lte的方法
* @param field 实体类字段
* @param value 值
*/
public Criteria<T> lte(boolean condition, SFunction<T, ?> field, Object value) {
if (condition) {this.lte(field, value);}
return this;
}
/**
* isNull查询
* 例子:
* hql写法 hql += "and id is null "
* 构造器写法 this.isNull(xx::getId);
* @param field 实体类字段
*/
public Criteria<T> isNull(SFunction<T, ?> field){
return this.isNull(getFieldName(field));
}
/**
* isNull查询
* 例子:
* hql写法 hql += "and id is not null "
* 构造器写法 this.isNotNull("id");
* @param field 实体类字段
*/
public Criteria<T> isNull(String field){
criterionList.add(new SimpleExpression(field, null, Criterion.Operator.ISNULL));
return this;
}
/**
* isNotNull查询
* 例子:
* hql写法 hql += "and id is not null "
* 构造器写法 this.isNotNull(xx::getId);
* @param field 实体类字段
*/
public Criteria<T> isNotNull(SFunction<T, ?> field){
return this.isNotNull(getFieldName(field));
}
/**
* isNotNull查询
* 例子:
* hql写法 hql += "and id is not null "
* 构造器写法 this.isNotNull("id");
* @param field 实体类字段
*/
public Criteria<T> isNotNull(String field){
criterionList.add(new SimpleExpression(field, null, Criterion.Operator.IS_NOTNULL));
return this;
}
/**
* isEmpty查询
* 例子:
* hql写法 hql += "and id = '' "
* 构造器写法 this.isEmpty(xx::getId);
* @param field 实体类字段
*/
public Criteria<T> isEmpty(SFunction<T, ?> field){
return this.isEmpty(getFieldName(field));
}
/**
* isEmpty查询
* 例子:
* hql写法 hql += "and id = '' "
* 构造器写法 this.isEmpty("id");
* @param field 实体类字段
*/
public Criteria<T> isEmpty(String field){
criterionList.add(new SimpleExpression(field, null, Criterion.Operator.IS_EMPTY));
return this;
}
/**
* isEmptyOrNull查询
* 例子:
* hql写法 hql += "and (id = '' or id is null)"
* 构造器写法 this.isEmptyOrNull("id");
* @param field 实体类字段
*/
public Criteria<T> isEmptyOrNull(String field){
Criteria<T> tCriteria = new Criteria<T>()
.isNull(field)
.isEmpty(field);
return this.or(tCriteria);
}
/**
* isEmptyOrNull查询
* 例子:
* hql写法 hql += "and (id = '' or id is null)"
* 构造器写法 this.isEmptyOrNull(xx::getId);
* @param field 实体类字段
*/
public Criteria<T> isEmptyOrNull(SFunction<T, ?> field){
return this.isEmptyOrNull(getFieldName(field));
}
/**
* isNotEmpty查询
* 例子:
* hql写法 hql += "and id != '' "
* 构造器写法 this.isNotEmpty(xx::getId);
* @param field 实体类字段
*/
public Criteria<T> isNotEmpty(SFunction<T, ?> field){
criterionList.add(new SimpleExpression(getFieldName(field), null, Criterion.Operator.IS_NOT_EMPTY));
return this;
}
/**
* isNotEmpty查询
* 例子:
* hql写法 hql += "and id != '' "
* 构造器写法 this.isNotEmpty("id");
* @param field 实体类字段
*/
public Criteria<T> isNotEmpty(String field){
criterionList.add(new SimpleExpression(field, null, Criterion.Operator.IS_NOT_EMPTY));
return this;
}
/**
* isNotEmptyAndNotNull查询
* 例子:
* hql写法 hql += "and (id != '' and id is not null)"
* 构造器写法 this.isNotEmptyAndNotNull(xx::getId);
* @param field 实体类字段
*/
public Criteria<T> isNotEmptyAndNotNull(SFunction<T, ?> field){
String fieldName = getFieldName(field);
return this.isNotEmptyAndNotNull(fieldName);
}
/**
* isNotEmptyAndNotNull查询
* 例子:
* hql写法 hql += "and (id != '' and id is not null)"
* 构造器写法 this.isNotEmptyAndNotNull("id");
* @param field 实体类字段
*/
public Criteria<T> isNotEmptyAndNotNull(String field){
Criteria<T> tCriteria = new Criteria<T>()
.isNotEmpty(field)
.isNotNull(field);
return this.add(tCriteria);
}
/**
* 降序
* 例子:
* hql写法 hql += "order by id desc"
* 构造器写法 this.orderByDesc(xx::getId);
* @param field 实体类字段
*/
public Criteria<T> orderByDesc(SFunction<T, ?> field) {
orderList.add(new SimpleExpression(getFieldName(field), null, Criterion.Operator.ORDER_BY_DESC));
return this;
}
/**
* 升序
* 例子:
* hql写法 hql += "order by id asc"
* 构造器写法 this.orderByAsc(xx::getId);
* @param field 实体类字段
*/
public Criteria<T> orderByAsc(SFunction<T, ?> field) {
orderList.add(new SimpleExpression(getFieldName(field), null, Criterion.Operator.ORDER_BY_ASC));
return this;
}
}
3. 创建SimpleExpression简单查询构建器,实现Criterion接口方法
/**
* @description 简单的条件表达式
*/
public class SimpleExpression implements Criterion {
/**
* 属性名
*/
private final String fieldName;
/**
* 对应值
*/
private final Object value;
/**
* 计算符
*/
private final Operator operator;
protected SimpleExpression(String fieldName, Object value, Operator operator) {
this.fieldName = fieldName;
this.value = value;
this.operator = operator;
}
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public Predicate toPredicate(Root<?> root,
CriteriaQuery<?> query,
CriteriaBuilder builder) {
Path expression = this.obtainPath(root);
switch (operator) {
case EQ:
return builder.equal(expression, value);
case NE:
return builder.notEqual(expression, value);
case LIKE:
return builder.like((Expression<String>) expression, "%" + value + "%");
case LEFT_LIKE:
return builder.like((Expression<String>) expression, "%" + value);
case RIGHT_LIKE:
return builder.like((Expression<String>) expression, value + "%");
case LT:
return builder.lessThan(expression, (Comparable) value);
case GT:
return builder.greaterThan(expression, (Comparable) value);
case LTE:
return builder.lessThanOrEqualTo(expression, (Comparable) value);
case GTE:
return builder.greaterThanOrEqualTo(expression, (Comparable) value);
case IN:
if (value instanceof Collection){
CriteriaBuilder.In in = builder.in(expression);
((Collection<?>) value).forEach(x->in.value(String.valueOf(x)));
return in;
}
throw new RuntimeException("无法处理非数组类型的数据");
case NOTIN:
if (value instanceof Collection){
CriteriaBuilder.In in = builder.in(expression);
((Collection<?>) value).forEach(x->in.value(String.valueOf(x)));
return builder.not(in);
}
throw new RuntimeException("无法处理非数组类型的数据");
case ISNULL:
return builder.isNull(expression);
case IS_NOTNULL:
return builder.isNotNull(expression);
case IS_EMPTY:
return builder.equal(expression,"");
case IS_NOT_EMPTY:
return builder.notEqual(expression,"");
default:
return null;
}
}
@Override
public Order toOrder(Root<?> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
Path expression = this.obtainPath(root);
switch (operator){
case ORDER_BY_DESC:
return builder.desc(expression);
case ORDER_BY_ASC:
return builder.asc(expression);
default:
return null;
}
}
/**
* 获取实体属性
*
* @param root
* @return
*/
private Path obtainPath(Root<?> root){
Path expression;
// 此处是表关联数据,现在想怎么关联就怎么关联,为爽而开发
// 例如 product查询父级品牌 .eq(parent.brand.nameCn."x")
// 查询 product的 parent 的 brand 的 nameCn 为 x
if (fieldName.contains(".")) {
String[] names = StringUtils.split(fieldName, ".");
// 先关联第一个属性字段
Join join = root.join(names[0], JoinType.LEFT);
// 循环到第n-1个属性字段
int namesLength = names.length - 1;
for (int i = 1; i < namesLength; i++) {
join = join.join(names[i], JoinType.LEFT);
}
// 末尾获取属性路径
expression = join.get(names[namesLength]);
} else {
//单表查询
expression = root.get(fieldName);
}
return expression;
}
}
4. 创建复杂的条件查询表达式,像一些and(id = 1 and nickname = 2)这样的查询条件
/**
* @description 复杂条件表达
*/
public class ComplexExpression implements Criterion {
/**
* 多条件表达式
*/
private final List<Criterion> criterionList;
/**
* 操作符
*/
private final Operator operator;
public ComplexExpression(List<Criterion> criterionList, Operator operator) {
this.criterionList = criterionList;
this.operator = operator;
}
@Override
public Predicate toPredicate(Root<?> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
List<Predicate> predicates = criterionList.stream().map(x -> x.toPredicate(root, query, builder)).collect(Collectors.toList());
switch (operator) {
case OR:
return builder.or(predicates.toArray(new Predicate[0]));
case AND:
return builder.and(predicates.toArray(new Predicate[0]));
default:
return null;
}
}
@Override
public Order toOrder(Root<?> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
// 在这个表达式中不应该出现排序
return null;
}
}
4. 最终实现效果
public List<User> loadByNicknameAndGender(String a,String b){
Criteria<User> criteria = new Criteria<User>()
.eq(StringUtil.isNotBlank(a),User::getNickname, a)
.eq(StringUtil.isNotBlank(b),User::getGender,b)
.orderByDesc(User::getId);
this.repository.findAll(criteria);
}
把代码统统'藏'起来,让代码更简洁和容易更改才是YYDS!