一个表中有多个字段需要支持查询,传多个字段到后台。
如果有很多这样子的场景,则每个查询都需要这样子实现。
LambdaQueryWrapper<Alarm> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(StringUtils.isNotBlank(alarmDelayQueryRequest.getId()), AlarmDelay::getId, alarmDelayQueryRequest.getId());
lambdaQueryWrapper.eq(Objects.nonNull(alarmDelayQueryRequest.getType()), AlarmDelay::getCreateType, alarmDelayQueryRequest.getType());
lambdaQueryWrapper.in(CollectionUtils.isNotEmpty(alarmDelayQueryRequest.getLevelList()), AlarmDelay::getLevel, alarmDelayQueryRequest.getLevelList());
lambdaQueryWrapper.like(StringUtils.isNotBlank(alarmDelayQueryRequest.getBusinessName()), AlarmDelay::getBusinessName, alarmDelayQueryRequest.getBusinessName());
lambdaQueryWrapper.like(StringUtils.isNotBlank(alarmDelayQueryRequest.getAppName()), AlarmDelay::getAppName, alarmDelayQueryRequest.getAppName());
lambdaQueryWrapper.like(StringUtils.isNotBlank(alarmDelayQueryRequest.getComponentName()), AlarmDelay::getComponentName, alarmDelayQueryRequest.getComponentName());
写一个工具类,处理所有类似的查询。
通过动态拼接查询条件,进行查询。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface QueryCustomAnnotation {
//属性名
String propName() default "";
//查询方式
Type type() default Type.LIKE;
//忽略不需要拼接的字段
boolean ignore() default false;
enum Type {
//等于
EQUAL
//大于等于
,GREATER_THAN
//小于等于
,LESS_THAN
//模糊查询
,LIKE
//左模糊查询
,LEFT_LIKE
//右模糊查询
,RIGHT_LIKE
//小于
,LESS_THAN_NQ
//大于
,GREATER_THAN_NQ
//包含
,IN
// 不等于
,NOT_EQUAL
// between
,BETWEEN
// 不为空
,NOT_NULL
}
}
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.pscsoft.da.common.annotation.QueryCustomAnnotation;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.utils.CollectionUtil;
import org.springframework.util.StringUtils;
import java.lang.invoke.CallSite;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
import java.util.*;
/**
*
* @author andy.cao
* @date 2022/10/10
*/
@Slf4j
public class MyBatisPlusQueryPlus {
private static final int FLAG_SERIALIZABLE = 1;
public static <R, Q> LambdaQueryWrapper getPredicate(R obj, Q query) {
LambdaQueryWrapper<R> queryWrapper = new LambdaQueryWrapper<>();
if (query == null) {
return queryWrapper;
}
try {
List<Field> fields = getAllFields(query.getClass(), new ArrayList<>());
for (Field field : fields) {
boolean accessible = field.isAccessible();
field.setAccessible(true);
QueryCustomAnnotation q = field.getAnnotation(QueryCustomAnnotation.class);
SFunction functionField = null;
Object val = field.get(query);
if (Objects.isNull(val) || "".equals(val)) {
continue;
}
//如果q为空,则走默认走模糊匹配
if (q == null){
functionField = getFunctionField(query.getClass(), field, null);
if (Objects.isNull(functionField)) {
continue;
}
queryWrapper.like(functionField, val);
break;
}
//是否定义忽略字段
if (q.ignore()){
continue;
}
String propName = q.propName();
String attributeName = StringUtils.isEmpty(propName) ? field.getName() : propName;
functionField = getFunctionField(query.getClass(), field, attributeName);
if (Objects.isNull(functionField)) {
continue;
}
switch (q.type()) {
case EQUAL:
//queryWrapper.and(wrapper -> wrapper.eq(finalAttributeName, val));
queryWrapper.eq(functionField, val);
break;
case GREATER_THAN:
queryWrapper.ge(functionField, val);
break;
case LESS_THAN:
queryWrapper.le(functionField, val);
break;
case LESS_THAN_NQ:
queryWrapper.lt(functionField, val);
case GREATER_THAN_NQ:
queryWrapper.gt(functionField, val);
break;
case LIKE:
queryWrapper.like(functionField, val);
break;
case LEFT_LIKE:
queryWrapper.likeLeft(functionField, val);
break;
case RIGHT_LIKE:
queryWrapper.likeRight(functionField, val);
break;
case IN:
if (CollectionUtil.isNotEmpty((Collection<Long>) val)) {
queryWrapper.in(functionField, (Collection<Long>) val);
}
break;
case NOT_EQUAL:
queryWrapper.ne(functionField, val);
break;
case NOT_NULL:
queryWrapper.isNotNull(functionField);
break;
case BETWEEN:
List<Object> between = new ArrayList<>((List<Object>) val);
queryWrapper.between(functionField, between.get(0), between.get(1));
break;
default:
break;
}
field.setAccessible(accessible);
}
} catch (Exception e) {
log.error("映射查询条件异常:{},{}", e.getMessage(), e);
}
return queryWrapper;
}
private static List<Field> getAllFields(Class clazz, List<Field> fields) {
if (clazz != null) {
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
//getAllFields(clazz.getSuperclass(), fields);
}
return fields;
}
public static SFunction getFunctionField(Class<?> entityClass, Field field, String filedName) {
final MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType methodType = MethodType.methodType(field.getType(), entityClass);
final CallSite site;
if (StringUtils.isEmpty(filedName)){
filedName = field.getName();
}
String getFunName = "get" + filedName.substring(0, 1).toUpperCase() + filedName.substring(1);
try {
site = LambdaMetafactory.altMetafactory(lookup,
"invoke",
MethodType.methodType(SFunction.class),
methodType,
lookup.findVirtual(entityClass, getFunName, MethodType.methodType(field.getType())),
methodType, FLAG_SERIALIZABLE);
SFunction func = (SFunction) site.getTarget().invokeExact();
return func;
} catch (Throwable e) {
//throw ExceptionUtils.mpe("This class %s is not have method %s ", entityClass.getName(), getFunName);
log.error("根据字段获取sfunc异常:{},{}", e.getMessage(), e);
}
return null;
}
@AllArgsConstructor
@NoArgsConstructor
@Data
public class AlarmRequest extends Query implements Serializable {
@QueryCustomAnnotation(ignore=true)
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "规则ID")
@QueryCustomAnnotation(type = QueryCustomAnnotation.Type.EQUAL)
private String id;
@ApiModelProperty(value = "创建方式")
@QueryCustomAnnotation(type = QueryCustomAnnotation.Type.EQUAL)
private Integer type;
@ApiModelProperty(value = "级别")
@QueryCustomAnnotation(propName = "level", type = QueryCustomAnnotation.Type.IN)
private List<Integer> levelList;
@ApiModelProperty(value = "key")
private String key;
//....省略
}
public IPage<AlarmDelay> selectAlarmList(AlarmRequest alarmRequest) {
LambdaQueryWrapper<Alarm> lambdaQueryWrapper = MyBatisPlusQueryPlus.getPredicate(Alarm.class, alarmRequest);
IPage<Alarm> page = alarmDelayMapper.selectPage(Condition.getPage(alarmRequest), lambdaQueryWrapper);
return page;
}