mybatisplus动态拼查询条件

场景

一个表中有多个字段需要支持查询,传多个字段到后台。

常规实现

如果有很多这样子的场景,则每个查询都需要这样子实现。
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());

工具类实现

写一个工具类,处理所有类似的查询。
通过动态拼接查询条件,进行查询。

  1. 定义注解
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
    }

}
  1. 工具类
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;
    }
  1. 请求参数
@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;
    
    //....省略
}
  1. 使用
  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;
   }
  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值