diff --git a/continew-starter-data/continew-starter-data-mybatis-plus/src/main/java/top/charles7c/continew/starter/data/mybatis/plus/query/Query.java b/continew-starter-data/continew-starter-data-mybatis-plus/src/main/java/top/charles7c/continew/starter/data/mybatis/plus/query/Query.java index 1a8e13d1..aa4947df 100644 --- a/continew-starter-data/continew-starter-data-mybatis-plus/src/main/java/top/charles7c/continew/starter/data/mybatis/plus/query/Query.java +++ b/continew-starter-data/continew-starter-data-mybatis-plus/src/main/java/top/charles7c/continew/starter/data/mybatis/plus/query/Query.java @@ -31,20 +31,15 @@ import java.lang.annotation.*; 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; - - /** - * 多属性模糊查询,仅支持 String 类型属性 - *

- * 例如:@Query(blurry = {"username", "email"}) 表示根据用户名和邮箱模糊查询 - *

- */ - String[] blurry() default {}; } diff --git a/continew-starter-data/continew-starter-data-mybatis-plus/src/main/java/top/charles7c/continew/starter/data/mybatis/plus/query/QueryHelper.java b/continew-starter-data/continew-starter-data-mybatis-plus/src/main/java/top/charles7c/continew/starter/data/mybatis/plus/query/QueryHelper.java index f6d51d55..3234042e 100644 --- a/continew-starter-data/continew-starter-data-mybatis-plus/src/main/java/top/charles7c/continew/starter/data/mybatis/plus/query/QueryHelper.java +++ b/continew-starter-data/continew-starter-data-mybatis-plus/src/main/java/top/charles7c/continew/starter/data/mybatis/plus/query/QueryHelper.java @@ -16,10 +16,10 @@ 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.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.ArrayUtils; import lombok.AccessLevel; import lombok.NoArgsConstructor; 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.util.ArrayList; import java.util.List; +import java.util.Objects; /** * 查询助手 @@ -71,15 +72,13 @@ public class QueryHelper { * @param 查询条件数据类型 * @param 查询数据类型 */ - private static void buildQuery(Q query, Field field, QueryWrapper queryWrapper) { + public static void buildQuery(Q query, Field field, QueryWrapper queryWrapper) { boolean accessible = field.canAccess(query); try { field.setAccessible(true); - // 没有 @Query,直接返回 - Query queryAnnotation = field.getAnnotation(Query.class); - if (null == queryAnnotation) { - return; - } + + String fieldName = field.getName(); + String columnName = StrUtil.toUnderlineCase(fieldName); // 如果字段值为空,直接返回 Object fieldValue = field.get(query); @@ -87,8 +86,58 @@ public class QueryHelper { 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 between = new ArrayList<>((List)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)fieldValue); + } + case NOT_IN -> { + ValidationUtils.throwIfEmpty(fieldValue, "[{}] 不能为空", fieldName); + queryWrapper.or().notIn(underline, (List)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) { log.error("Build query occurred an validation error: {}. Query: {}, Field: {}.", e .getMessage(), query, field, e); @@ -103,34 +152,18 @@ public class QueryHelper { /** * 解析查询条件 * - * @param queryAnnotation 查询注解 - * @param fieldName 字段名 - * @param fieldValue 字段值 - * @param queryWrapper MyBatis Plus 查询条件封装对象 - * @param 查询数据类型 + * @param queryType 查询类型 + * @param columnName 驼峰字段名 + * @param fieldValue 字段值 + * @param queryWrapper MyBatis Plus 查询条件封装对象 + * @param 查询数据类型 */ - private static void parse(Query queryAnnotation, - String fieldName, + private static void parse(QueryType queryType, + String columnName, Object fieldValue, QueryWrapper 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) { case EQUAL -> queryWrapper.eq(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 BETWEEN -> { List between = new ArrayList<>((List)fieldValue); - ValidationUtils.throwIf(between.size() != 2, "[{}] 必须是一个范围", fieldName); + ValidationUtils.throwIf(between.size() != 2, "[{}] 必须是一个范围", columnName); queryWrapper.between(columnName, between.get(0), between.get(1)); } case LEFT_LIKE -> queryWrapper.likeLeft(columnName, fieldValue); case INNER_LIKE -> queryWrapper.like(columnName, fieldValue); case RIGHT_LIKE -> queryWrapper.likeRight(columnName, fieldValue); case IN -> { - ValidationUtils.throwIfEmpty(fieldValue, "[{}] 不能为空", fieldName); + ValidationUtils.throwIfEmpty(fieldValue, "[{}] 不能为空", columnName); queryWrapper.in(columnName, (List)fieldValue); } case NOT_IN -> { - ValidationUtils.throwIfEmpty(fieldValue, "[{}] 不能为空", fieldName); + ValidationUtils.throwIfEmpty(fieldValue, "[{}] 不能为空", columnName); queryWrapper.notIn(columnName, (List)fieldValue); } case IS_NULL -> queryWrapper.isNull(columnName); diff --git a/continew-starter-extension/continew-starter-extension-crud/src/main/java/top/charles7c/continew/starter/extension/crud/base/BaseServiceImpl.java b/continew-starter-extension/continew-starter-extension-crud/src/main/java/top/charles7c/continew/starter/extension/crud/base/BaseServiceImpl.java index a29416dd..fa0bd810 100644 --- a/continew-starter-extension/continew-starter-extension-crud/src/main/java/top/charles7c/continew/starter/extension/crud/base/BaseServiceImpl.java +++ b/continew-starter-extension/continew-starter-extension-crud/src/main/java/top/charles7c/continew/starter/extension/crud/base/BaseServiceImpl.java @@ -76,11 +76,13 @@ public abstract class BaseServiceImpl, T extends BaseDO, protected final Class entityClass = this.currentEntityClass(); protected final Class listClass = this.currentListClass(); protected final Class detailClass = this.currentDetailClass(); + protected final Class queryClass = this.currentQueryClass(); private final Field[] entityFields = this.entityClass.getDeclaredFields(); + private final List queryFields = ReflectUtils.getNonStaticFields(queryClass); @Override public PageResp page(Q query, PageQuery pageQuery) { - QueryWrapper queryWrapper = QueryHelper.build(query); + QueryWrapper queryWrapper = handleQueryWrapper(query); IPage page = baseMapper.selectPage(pageQuery.toPage(), queryWrapper); PageResp pageResp = PageResp.build(page, listClass); pageResp.getList().forEach(this::fill); @@ -133,7 +135,7 @@ public abstract class BaseServiceImpl, T extends BaseDO, * @return 列表信息 */ protected List list(Q query, SortQuery sortQuery, Class targetClass) { - QueryWrapper queryWrapper = QueryHelper.build(query); + QueryWrapper queryWrapper = handleQueryWrapper(query); // 设置排序 this.sort(queryWrapper, sortQuery); List entityList = baseMapper.selectList(queryWrapper); @@ -246,6 +248,22 @@ public abstract class BaseServiceImpl, T extends BaseDO, return entity; } + /** + * 获取当前详情信息类型 + * + * @return 当前详情信息类型 + */ + protected QueryWrapper handleQueryWrapper(Q query) { + QueryWrapper 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, T extends BaseDO, protected Class currentDetailClass() { return (Class)this.typeArguments[3]; } + + /** + * 获取当前查询类型 + * + * @return 当前查询类型 + */ + protected Class currentQueryClass() { + return (Class)this.typeArguments[4]; + } }