转载

用注解实现一行代码构建QueryWrapper

实现效果

一行代码调用效果:

QueryWrapper<Department> queryWrapper = QueryBuilder.toQueryWrapper(departmentDto);

//dto中的注解示例

public class DepartmentDto {
 // 默认equals比较,无需指定
 private Long parentId;

 //指定条件匹配方式
 @BindQuery(comparison = Comparison.CONTAINS)
 private String name;
}

封装背景:

Mybatis-plus的查询构造器可以方便的构建单表的SQL查询,你可以在controller里接收到请求参数然后转成查询条件,比如部门的搜索查询代码类似这样:

DepartmentDTO dto = …;
LambdaQueryWrapper<Department> queryWrapper = new QueryWrapper<Department>().lambda();
if(dto.getOrgId() != null){
    queryWrapper.eq(Department::getOrgId, dto.getOrgId());
}
if(dto.getName() != null){
    queryWrapper.like(Department::getName, dto.getName());
}

其他对象的查询代码也极为相似,差异无非是对象不同、字段不同,如何提供更简单通用的解决方案呢?

可以通过注解实现。

实现步骤

1. 定义注解及匹配方式枚举

首先,定义注解及支持的匹配方式枚举。

匹配方式枚举定义:

public enum Comparison {
     EQ, // 相等,默认
     IN, // IN
     STARTSWITH, //以xx起始
     CONTAINS, //包含,等同LIKE
     GT, // 大于
     GE, // 大于等于
     LT, // 小于
     LE // 小于等于
}

注解定义 :

(参与查询的大多数场景是匹配条件为“=相等”,为了减少代码量,我们默认无注解即为“相等”)

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface BindQuery {
     /**
      * 查询条件匹配方式
      */
     Comparison comparison() default Comparison.EQ;
}

2. 封装工具类提取非空字段

在DTO中有值的字段才需要参与查询,这需要我们提供一个方法提取dto中的非空字段和值。

示例代码:

/**
 * 提取非空字段及值
 */
 private static <DTO> LinkedHashMap<String, Object> extractNotNullValues(DTO dto){
     LinkedHashMap<String, Object> resultMap = new LinkedHashMap<>();
     Class<?> dtoClass = dto.getClass();
     // 转换
     List<Field> declaredFields = BeanUtils.extractAllFields(dtoClass);
     for (Field field : declaredFields) {
         //忽略static,以及final,transient
         boolean isStatic = Modifier.isStatic(field.getModifiers());
         boolean isFinal = Modifier.isFinal(field.getModifiers());
         boolean isTransient = Modifier.isTransient(field.getModifiers());
         if (isStatic || isFinal || isTransient) {
            continue;
         }
         //打开私有访问 获取值
         field.setAccessible(true);
         Object value = field.get(dto);
         if (value != null) {
            resultMap.put(field.getName(), value);
         }
     }
     return resultMap;
}

3. 基于注解将非空字段构建为查询条件

最后,实现提取非空字段,基于注解匹配方式,构建QueryWrapper:

/**
 * 转换具体实现
 */
 private static <DTO> QueryWrapper<DTO> dtoToWrapper(DTO dto){
    QueryWrapper wrapper = new QueryWrapper<>();
    // 转换
    LinkedHashMap<String, Object> fieldValuesMap = extractNotNullValues(dto);
    if(V.isEmpty(fieldValuesMap)){
        return wrapper;
    }
    // 构建QueryWrapper
    for(Map.Entry<String, Object> entry : fieldValuesMap.entrySet()){
        Field field = BeanUtils.extractField(dto.getClass(), entry.getKey());
        Object value = entry.getValue();
        // 字段名转换为列名
        String columnName = getColumnName(field);
        // 对比类型
        Comparison comparison = Comparison.EQ;
        switch (comparison) {
            case EQ:
                wrapper.eq(columnName, value);
            break;
            case GT:
                wrapper.gt(columnName, value);
                break;
            ... //其他匹配条件   
        }
    }
    return wrapper;
 }

更多极简封装,请关注diboot github

Diboot - 为开发人员打造的低代码开发平台

原文  https://segmentfault.com/a/1190000023091700
正文到此结束
Loading...