实现效果
一行代码调用效果:
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;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。