mirror of
https://github.com/continew-org/continew-starter.git
synced 2025-09-10 20:57:18 +08:00
refactor: 优化 Query 注解查询
* @Query 注解删除了blurry字段,并且修改了字段名称及类型为数组;
This commit is contained in:
@@ -31,20 +31,15 @@ import java.lang.annotation.*;
|
|||||||
public @interface Query {
|
public @interface Query {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 属性名(默认和使用该注解的属性的名称一致)
|
* 属性名数组
|
||||||
|
* columns为空 走实体类的字段,并且根据queryType来查询;
|
||||||
|
* columns不为空且columns长度为1,走columns[0]的字段,并且根据queryType来查询;
|
||||||
|
* columns不为空且columns长度大于1,走columns的所有字段, 并且根据queryType来查询; columns之间的处理是OR操作。
|
||||||
*/
|
*/
|
||||||
String property() default "";
|
String[] columns() default {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询类型(等值查询、模糊查询、范围查询等)
|
* 查询类型(等值查询、模糊查询、范围查询等)
|
||||||
*/
|
*/
|
||||||
QueryType type() default QueryType.EQUAL;
|
QueryType type() default QueryType.EQUAL;
|
||||||
|
|
||||||
/**
|
|
||||||
* 多属性模糊查询,仅支持 String 类型属性
|
|
||||||
* <p>
|
|
||||||
* 例如:@Query(blurry = {"username", "email"}) 表示根据用户名和邮箱模糊查询
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
String[] blurry() default {};
|
|
||||||
}
|
}
|
||||||
|
@@ -16,10 +16,10 @@
|
|||||||
|
|
||||||
package top.charles7c.continew.starter.data.mybatis.plus.query;
|
package top.charles7c.continew.starter.data.mybatis.plus.query;
|
||||||
|
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.ArrayUtils;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -30,6 +30,7 @@ import top.charles7c.continew.starter.core.util.validate.ValidationUtils;
|
|||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询助手
|
* 查询助手
|
||||||
@@ -71,15 +72,13 @@ public class QueryHelper {
|
|||||||
* @param <Q> 查询条件数据类型
|
* @param <Q> 查询条件数据类型
|
||||||
* @param <R> 查询数据类型
|
* @param <R> 查询数据类型
|
||||||
*/
|
*/
|
||||||
private static <Q, R> void buildQuery(Q query, Field field, QueryWrapper<R> queryWrapper) {
|
public static <Q, R> void buildQuery(Q query, Field field, QueryWrapper<R> queryWrapper) {
|
||||||
boolean accessible = field.canAccess(query);
|
boolean accessible = field.canAccess(query);
|
||||||
try {
|
try {
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
// 没有 @Query,直接返回
|
|
||||||
Query queryAnnotation = field.getAnnotation(Query.class);
|
String fieldName = field.getName();
|
||||||
if (null == queryAnnotation) {
|
String columnName = StrUtil.toUnderlineCase(fieldName);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果字段值为空,直接返回
|
// 如果字段值为空,直接返回
|
||||||
Object fieldValue = field.get(query);
|
Object fieldValue = field.get(query);
|
||||||
@@ -87,8 +86,58 @@ public class QueryHelper {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取 Query 注解信息
|
||||||
|
Query queryAnnotation = field.getAnnotation(Query.class);
|
||||||
|
// 没有@Query注解,默认走实体类的字段 EQ精确 查询;
|
||||||
|
if (Objects.isNull(queryAnnotation)) {
|
||||||
|
queryWrapper.eq(columnName, fieldValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] columns = queryAnnotation.columns();
|
||||||
|
if (ArrayUtils.isEmpty(columns)) {
|
||||||
|
columnName = StrUtil.toUnderlineCase(columnName);
|
||||||
|
} else if (columns.length == 1) {
|
||||||
|
columnName = StrUtil.toUnderlineCase(columns[0]);
|
||||||
|
} else {
|
||||||
|
QueryType queryType = queryAnnotation.type();
|
||||||
|
queryWrapper.and(wrapper -> {
|
||||||
|
for (String column : columns) {
|
||||||
|
String underline = StrUtil.toUnderlineCase(column);
|
||||||
|
// 解析多属性查询
|
||||||
|
switch (queryType) {
|
||||||
|
case EQUAL -> queryWrapper.or().eq(underline, fieldValue);
|
||||||
|
case NOT_EQUAL -> queryWrapper.or().ne(underline, fieldValue);
|
||||||
|
case GREATER_THAN -> queryWrapper.or().gt(underline, fieldValue);
|
||||||
|
case LESS_THAN -> queryWrapper.or().lt(underline, fieldValue);
|
||||||
|
case GREATER_THAN_OR_EQUAL -> queryWrapper.or().ge(underline, fieldValue);
|
||||||
|
case LESS_THAN_OR_EQUAL -> queryWrapper.or().le(underline, fieldValue);
|
||||||
|
case BETWEEN -> {
|
||||||
|
List<Object> between = new ArrayList<>((List<Object>)fieldValue);
|
||||||
|
ValidationUtils.throwIf(between.size() != 2, "[{}] 必须是一个范围", fieldName);
|
||||||
|
queryWrapper.or().between(underline, between.get(0), between.get(1));
|
||||||
|
}
|
||||||
|
case LEFT_LIKE -> queryWrapper.or().likeLeft(underline, fieldValue);
|
||||||
|
case INNER_LIKE -> queryWrapper.or().like(underline, fieldValue);
|
||||||
|
case RIGHT_LIKE -> queryWrapper.or().likeRight(underline, fieldValue);
|
||||||
|
case IN -> {
|
||||||
|
ValidationUtils.throwIfEmpty(fieldValue, "[{}] 不能为空", fieldName);
|
||||||
|
queryWrapper.or().in(underline, (List<Object>)fieldValue);
|
||||||
|
}
|
||||||
|
case NOT_IN -> {
|
||||||
|
ValidationUtils.throwIfEmpty(fieldValue, "[{}] 不能为空", fieldName);
|
||||||
|
queryWrapper.or().notIn(underline, (List<Object>)fieldValue);
|
||||||
|
}
|
||||||
|
case IS_NULL -> queryWrapper.or().isNull(underline);
|
||||||
|
case IS_NOT_NULL -> queryWrapper.or().isNotNull(underline);
|
||||||
|
default -> throw new IllegalArgumentException(String.format("暂不支持 [%s] 查询类型", queryType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
// 解析查询条件
|
// 解析查询条件
|
||||||
parse(queryAnnotation, field.getName(), fieldValue, queryWrapper);
|
parse(queryAnnotation.type(), columnName, fieldValue, queryWrapper);
|
||||||
} catch (BadRequestException e) {
|
} catch (BadRequestException e) {
|
||||||
log.error("Build query occurred an validation error: {}. Query: {}, Field: {}.", e
|
log.error("Build query occurred an validation error: {}. Query: {}, Field: {}.", e
|
||||||
.getMessage(), query, field, e);
|
.getMessage(), query, field, e);
|
||||||
@@ -103,34 +152,18 @@ public class QueryHelper {
|
|||||||
/**
|
/**
|
||||||
* 解析查询条件
|
* 解析查询条件
|
||||||
*
|
*
|
||||||
* @param queryAnnotation 查询注解
|
* @param queryType 查询类型
|
||||||
* @param fieldName 字段名
|
* @param columnName 驼峰字段名
|
||||||
* @param fieldValue 字段值
|
* @param fieldValue 字段值
|
||||||
* @param queryWrapper MyBatis Plus 查询条件封装对象
|
* @param queryWrapper MyBatis Plus 查询条件封装对象
|
||||||
* @param <R> 查询数据类型
|
* @param <R> 查询数据类型
|
||||||
*/
|
*/
|
||||||
private static <R> void parse(Query queryAnnotation,
|
private static <R> void parse(QueryType queryType,
|
||||||
String fieldName,
|
String columnName,
|
||||||
Object fieldValue,
|
Object fieldValue,
|
||||||
QueryWrapper<R> queryWrapper) {
|
QueryWrapper<R> queryWrapper) {
|
||||||
// 解析多属性模糊查询
|
|
||||||
// 如果设置了多属性模糊查询,分割属性进行条件拼接
|
|
||||||
String[] blurryPropertyArr = queryAnnotation.blurry();
|
|
||||||
if (ArrayUtil.isNotEmpty(blurryPropertyArr)) {
|
|
||||||
queryWrapper.and(wrapper -> {
|
|
||||||
for (String blurryProperty : blurryPropertyArr) {
|
|
||||||
wrapper.or().like(StrUtil.toUnderlineCase(blurryProperty), fieldValue);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解析单个属性查询
|
// 解析单个属性查询
|
||||||
// 如果没有单独指定属性名,就和使用该注解的属性的名称一致
|
|
||||||
// 注意:数据库规范中列采用下划线连接法命名,程序规范中变量采用驼峰法命名
|
// 注意:数据库规范中列采用下划线连接法命名,程序规范中变量采用驼峰法命名
|
||||||
String property = queryAnnotation.property();
|
|
||||||
String columnName = StrUtil.toUnderlineCase(StrUtil.blankToDefault(property, fieldName));
|
|
||||||
QueryType queryType = queryAnnotation.type();
|
|
||||||
switch (queryType) {
|
switch (queryType) {
|
||||||
case EQUAL -> queryWrapper.eq(columnName, fieldValue);
|
case EQUAL -> queryWrapper.eq(columnName, fieldValue);
|
||||||
case NOT_EQUAL -> queryWrapper.ne(columnName, fieldValue);
|
case NOT_EQUAL -> queryWrapper.ne(columnName, fieldValue);
|
||||||
@@ -140,18 +173,18 @@ public class QueryHelper {
|
|||||||
case LESS_THAN_OR_EQUAL -> queryWrapper.le(columnName, fieldValue);
|
case LESS_THAN_OR_EQUAL -> queryWrapper.le(columnName, fieldValue);
|
||||||
case BETWEEN -> {
|
case BETWEEN -> {
|
||||||
List<Object> between = new ArrayList<>((List<Object>)fieldValue);
|
List<Object> between = new ArrayList<>((List<Object>)fieldValue);
|
||||||
ValidationUtils.throwIf(between.size() != 2, "[{}] 必须是一个范围", fieldName);
|
ValidationUtils.throwIf(between.size() != 2, "[{}] 必须是一个范围", columnName);
|
||||||
queryWrapper.between(columnName, between.get(0), between.get(1));
|
queryWrapper.between(columnName, between.get(0), between.get(1));
|
||||||
}
|
}
|
||||||
case LEFT_LIKE -> queryWrapper.likeLeft(columnName, fieldValue);
|
case LEFT_LIKE -> queryWrapper.likeLeft(columnName, fieldValue);
|
||||||
case INNER_LIKE -> queryWrapper.like(columnName, fieldValue);
|
case INNER_LIKE -> queryWrapper.like(columnName, fieldValue);
|
||||||
case RIGHT_LIKE -> queryWrapper.likeRight(columnName, fieldValue);
|
case RIGHT_LIKE -> queryWrapper.likeRight(columnName, fieldValue);
|
||||||
case IN -> {
|
case IN -> {
|
||||||
ValidationUtils.throwIfEmpty(fieldValue, "[{}] 不能为空", fieldName);
|
ValidationUtils.throwIfEmpty(fieldValue, "[{}] 不能为空", columnName);
|
||||||
queryWrapper.in(columnName, (List<Object>)fieldValue);
|
queryWrapper.in(columnName, (List<Object>)fieldValue);
|
||||||
}
|
}
|
||||||
case NOT_IN -> {
|
case NOT_IN -> {
|
||||||
ValidationUtils.throwIfEmpty(fieldValue, "[{}] 不能为空", fieldName);
|
ValidationUtils.throwIfEmpty(fieldValue, "[{}] 不能为空", columnName);
|
||||||
queryWrapper.notIn(columnName, (List<Object>)fieldValue);
|
queryWrapper.notIn(columnName, (List<Object>)fieldValue);
|
||||||
}
|
}
|
||||||
case IS_NULL -> queryWrapper.isNull(columnName);
|
case IS_NULL -> queryWrapper.isNull(columnName);
|
||||||
|
@@ -76,11 +76,13 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseDO,
|
|||||||
protected final Class<T> entityClass = this.currentEntityClass();
|
protected final Class<T> entityClass = this.currentEntityClass();
|
||||||
protected final Class<L> listClass = this.currentListClass();
|
protected final Class<L> listClass = this.currentListClass();
|
||||||
protected final Class<D> detailClass = this.currentDetailClass();
|
protected final Class<D> detailClass = this.currentDetailClass();
|
||||||
|
protected final Class<Q> queryClass = this.currentQueryClass();
|
||||||
private final Field[] entityFields = this.entityClass.getDeclaredFields();
|
private final Field[] entityFields = this.entityClass.getDeclaredFields();
|
||||||
|
private final List<Field> queryFields = ReflectUtils.getNonStaticFields(queryClass);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageResp<L> page(Q query, PageQuery pageQuery) {
|
public PageResp<L> page(Q query, PageQuery pageQuery) {
|
||||||
QueryWrapper<T> queryWrapper = QueryHelper.build(query);
|
QueryWrapper<T> queryWrapper = handleQueryWrapper(query);
|
||||||
IPage<T> page = baseMapper.selectPage(pageQuery.toPage(), queryWrapper);
|
IPage<T> page = baseMapper.selectPage(pageQuery.toPage(), queryWrapper);
|
||||||
PageResp<L> pageResp = PageResp.build(page, listClass);
|
PageResp<L> pageResp = PageResp.build(page, listClass);
|
||||||
pageResp.getList().forEach(this::fill);
|
pageResp.getList().forEach(this::fill);
|
||||||
@@ -133,7 +135,7 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseDO,
|
|||||||
* @return 列表信息
|
* @return 列表信息
|
||||||
*/
|
*/
|
||||||
protected <E> List<E> list(Q query, SortQuery sortQuery, Class<E> targetClass) {
|
protected <E> List<E> list(Q query, SortQuery sortQuery, Class<E> targetClass) {
|
||||||
QueryWrapper<T> queryWrapper = QueryHelper.build(query);
|
QueryWrapper<T> queryWrapper = handleQueryWrapper(query);
|
||||||
// 设置排序
|
// 设置排序
|
||||||
this.sort(queryWrapper, sortQuery);
|
this.sort(queryWrapper, sortQuery);
|
||||||
List<T> entityList = baseMapper.selectList(queryWrapper);
|
List<T> entityList = baseMapper.selectList(queryWrapper);
|
||||||
@@ -246,6 +248,22 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseDO,
|
|||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前详情信息类型
|
||||||
|
*
|
||||||
|
* @return 当前详情信息类型
|
||||||
|
*/
|
||||||
|
protected QueryWrapper<T> handleQueryWrapper(Q query) {
|
||||||
|
QueryWrapper<T> queryWrapper = new QueryWrapper<>();
|
||||||
|
// 没有查询条件,直接返回
|
||||||
|
if (null == query) {
|
||||||
|
return queryWrapper;
|
||||||
|
}
|
||||||
|
// 获取查询条件中所有的字段
|
||||||
|
queryFields.forEach(field -> QueryHelper.buildQuery(query, field, queryWrapper));
|
||||||
|
return queryWrapper;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增前置处理
|
* 新增前置处理
|
||||||
*
|
*
|
||||||
@@ -323,4 +341,13 @@ public abstract class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseDO,
|
|||||||
protected Class<D> currentDetailClass() {
|
protected Class<D> currentDetailClass() {
|
||||||
return (Class<D>)this.typeArguments[3];
|
return (Class<D>)this.typeArguments[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前查询类型
|
||||||
|
*
|
||||||
|
* @return 当前查询类型
|
||||||
|
*/
|
||||||
|
protected Class<Q> currentQueryClass() {
|
||||||
|
return (Class<Q>)this.typeArguments[4];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user