基于MyBatisPlus实现对单表的条件查询封装
当时写一些条件查询觉得使用
if (dto.getXXX != null) {
wrapper.eq(X::getXX,dto.getXXX);
}
这种垃圾代码写得我很难受,然后就想着自己封装一个工具类,然后就有这个东西了
如果你的能力强一点,能改成多表的连接查询,请务必告诉我,让我学一下!!!!
条件构造器工具类 - 通过注解自动封装构造器的查询条件
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tiyaa.backend.annotations.Wrapper;
import com.tiyaa.backend.factory.WrapperPatternFactory;
import org.apache.commons.lang3.StringUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
/**
* @author Chensw
* @className QueryWrapperUtils
* @date 2023/6/9
* @description 条件构造器工具类 - 通过注解自动封装构造器的查询条件
*/
public class QueryWrapperUtils {
/**
* 策略条件匹配工厂
*/
private static WrapperPatternFactory patternFactory = WrapperPatternFactory.getInstance();
public static QueryWrapperUtils getInstance() {
return new QueryWrapperUtils();
}
/**
* 条件构造方法
* @param queryWrapper 条件构造器
* @param object 查询的实体类
* @author Chensw
* @date 2023/6/12
*/
public static <T, R> QueryWrapper<T> wrapper(QueryWrapper<T> queryWrapper, R object) {
if (object == null) {
return queryWrapper;
}
Class<?> clazz = object.getClass();
// 获取全部的字段
Field[] fields = clazz.getDeclaredFields();
if (fields.length == 0) {
return queryWrapper;
}
for (Field field : fields) {
field.setAccessible(true);
// 获取全部注解
Annotation[] annotations = field.getAnnotations();
// 当没有注解就去掉
if (annotations.length == 0) {
break;
}
// 匹配注解的执行
for (Annotation annotation : annotations) {
if (annotation instanceof Wrapper) {
Wrapper wrapper = (Wrapper) annotation;
String columnName = wrapper.columnName();
// 获取字段内容
Object value;
try {
value = field.get(object);
if (value != null && StringUtils.isNotBlank(value.toString())) {
// 配置条件构造方式
patternFactory.pattern(wrapper.type(), queryWrapper, columnName, value);
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}
return queryWrapper;
}
}
匹配策略工厂
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.tiyaa.backend.annotations.Wrapper;
import com.tiyaa.backend.factory.service.WrapperPatternStrategy;
import java.util.HashMap;
/**
* @author Chensw
* @className WrapperPatternFactory
* @date 2023/6/12
* @description 匹配策略工厂
*/
public class WrapperPatternFactory {
/**
* 策略方法的容器
*/
private static HashMap<Wrapper.Type, WrapperPatternStrategy> map;
public static WrapperPatternFactory getInstance() {
return new WrapperPatternFactory();
}
public WrapperPatternFactory() {
init();
}
/**
* 初始化工厂
*/
private static void init() {
map = new HashMap<>(8);
// 匹配策略
map.put(Wrapper.Type.EQUALS, (queryWrapper, columnName, value) -> queryWrapper.eq(columnName, value));
map.put(Wrapper.Type.NOT_EQUALS, (queryWrapper, columnName, value) -> queryWrapper.ne(columnName, value));
map.put(Wrapper.Type.LIKE, (queryWrapper, columnName, value) -> queryWrapper.like(columnName, value));
map.put(Wrapper.Type.NOT_LIKE, (queryWrapper, columnName, value) -> queryWrapper.notLike(columnName, value));
map.put(Wrapper.Type.LE, (queryWrapper, columnName, value) -> queryWrapper.le(columnName, value));
map.put(Wrapper.Type.GE, (queryWrapper, columnName, value) -> queryWrapper.ge(columnName, value));
map.put(Wrapper.Type.LT, (queryWrapper, columnName, value) -> queryWrapper.lt(columnName, value));
map.put(Wrapper.Type.GT, (queryWrapper, columnName, value) -> queryWrapper.gt(columnName, value));
map.put(Wrapper.Type.IN, (queryWrapper, columnName, value) -> queryWrapper.in(columnName, value));
map.put(Wrapper.Type.NOT_IN, (queryWrapper, columnName, value) -> queryWrapper.notIn(columnName, value));
}
/**
* 匹配方法
* @param type 类型
* @param queryWrapper 条件构造器
* @param columnName 列名
* @param value 值
* @author Chensw
* @date 2023/6/12
*/
public void pattern(Wrapper.Type type, QueryWrapper queryWrapper, String columnName, Object value) {
WrapperPatternStrategy patternStrategy = map.get(type);
if (patternStrategy != null) {
patternStrategy.wrapper(queryWrapper, columnName, value);
}
}
}
枚举注解
import java.lang.annotation.*;
/**
* @author Chensw
* @className Equals
* @date 2023/6/9
* @description
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
@Documented
public @interface Wrapper {
/**
* 是否相等 true为eq false为ne
*/
boolean value() default true;
/**
* 字段名
*/
String columnName() default "";
/**
* 类型
*/
Type type() default Type.EQUALS;
/**
* 枚举
*/
enum Type {
// eq
EQUALS,
// like
LIKE,
// ne
NOT_EQUALS,
// not_like
NOT_LIKE,
// le
LE,
// ge
GE,
// lt
LT,
// gt
GT,
// in
IN,
// not_in
NOT_IN,
;
}
}
接口
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
/**
* @author Chensw
* @className WrapperPatternStrategy
* @date 2023/6/12
* @description 封装匹配策略接口
*/
public interface WrapperPatternStrategy {
/**
* 封装匹配策略
* @param columnName 列名
* @param value 值
* @param queryWrapper 条件构造器
* @author Chensw
* @date 2023/6/12
*/
void wrapper(QueryWrapper queryWrapper, String columnName, Object value);
}
最后看一下使用方式
这里需要在字段上标识好需要采用的匹配策略,是eq还是ne啥的,columnName也是需要编写清楚,否则在
QueryWrapperUtils类中的wrapper方法会出现找不到需要映射的字段名
@Wrapper(type = Wrapper.Type.EQUALS, columnName = "pay_id")
@Schema(description = "支付id/第三方支付标识")
private String payId;
@Wrapper(type = Wrapper.Type.EQUALS, columnName = "pay_time")
@Schema(description = "支付时间")
private LocalDateTime payTime;
@Wrapper(type = Wrapper.Type.EQUALS, columnName = "created_at")
调用方式
@Operation(summary = "分页查询消费时间" )
@PostMapping("/page" )
@PreAuthorize("hasAuthority('consumption:page')")
public IPage<Consumption> page(@RequestBody SearchConsumptionDTO dto) {
QueryWrapper<Consumption> queryWrapper = QueryWrapperUtils.wrapper(new QueryWrapper<>(), dto);
// 这里可以进行你需要的再一次扩展比如排序啥的
return consumptionService.page(dto.page(), queryWrapper);
}
其实可以不需要columnName写上映射字段,String columnName = wrapper.columnName(); 这句获取字段映射名字的代码其实下方的 ‘field’ 字段已经可以获取到字段的名称,可以将字段通过大写转成 _ + 小写字母 的方式来获取字段的默认名称,如果需要可自行修改,这个玩意我也不想去动他了,反正也是闲着无聊拿来练手用的
-如果什么地方做的不好,别喷我,只是个毕业1年的菜🐔