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 aa4947df..7b6ec2f2 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 @@ -21,8 +21,9 @@ import java.lang.annotation.*; /** * 查询注解 * - * @author Zheng Jie(ELADMIN) * @author Charles7c + * @author Jasmine + * @author Zheng Jie(ELADMIN) * @since 1.0.0 */ @Target(ElementType.FIELD) @@ -31,15 +32,17 @@ import java.lang.annotation.*; public @interface Query { /** - * 属性名数组 - * columns为空 走实体类的字段,并且根据queryType来查询; - * columns不为空且columns长度为1,走columns[0]的字段,并且根据queryType来查询; - * columns不为空且columns长度大于1,走columns的所有字段, 并且根据queryType来查询; columns之间的处理是OR操作。 + * 列名 + * + *

+ * columns 为空时,默认取值字段名(自动转换为下划线命名);
+ * columns 不为空且 columns 长度大于 1,多个列查询条件之间为或关系(OR)。 + *

*/ String[] columns() default {}; /** * 查询类型(等值查询、模糊查询、范围查询等) */ - QueryType type() default QueryType.EQUAL; + QueryType type() default QueryType.EQ; } 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 3234042e..f87f667a 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,13 +30,13 @@ 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; /** * 查询助手 * - * @author Zheng Jie(ELADMIN) * @author Charles7c + * @author Jasmine + * @author Zheng Jie(ELADMIN) * @since 1.0.0 */ @Slf4j @@ -44,12 +44,12 @@ import java.util.Objects; public class QueryHelper { /** - * 根据查询条件构建 MyBatis Plus 查询条件封装对象 + * 根据查询条件构建查询条件封装对象 * * @param query 查询条件 * @param 查询条件数据类型 * @param 查询数据类型 - * @return MyBatis Plus 查询条件封装对象 + * @return 查询条件封装对象 */ public static QueryWrapper build(Q query) { QueryWrapper queryWrapper = new QueryWrapper<>(); @@ -57,87 +57,80 @@ public class QueryHelper { if (null == query) { return queryWrapper; } - // 获取查询条件中所有的字段 + // 解析并拼接查询条件 List fieldList = ReflectUtils.getNonStaticFields(query.getClass()); - fieldList.forEach(field -> buildQuery(query, field, queryWrapper)); + fieldList.forEach(field -> buildWrapper(query, field, queryWrapper)); return queryWrapper; } /** - * 构建 MyBatis Plus 查询条件封装对象 + * 构建查询条件封装对象 * * @param query 查询条件 * @param field 字段 - * @param queryWrapper MyBatis Plus 查询条件封装对象 + * @param queryWrapper 查询条件封装对象 * @param 查询条件数据类型 * @param 查询数据类型 */ - public static void buildQuery(Q query, Field field, QueryWrapper queryWrapper) { + public static void buildWrapper(Q query, Field field, QueryWrapper queryWrapper) { boolean accessible = field.canAccess(query); try { field.setAccessible(true); - - String fieldName = field.getName(); - String columnName = StrUtil.toUnderlineCase(fieldName); - // 如果字段值为空,直接返回 Object fieldValue = field.get(query); if (ObjectUtil.isEmpty(fieldValue)) { return; } - - // 获取 Query 注解信息 + // 建议:数据库规范中列建议采用下划线连接法命名,程序规范中变量建议采用驼峰法命名 + String fieldName = field.getName(); + String columnName = StrUtil.toUnderlineCase(fieldName); + // 没有 @Query 注解,默认等值查询 Query queryAnnotation = field.getAnnotation(Query.class); - // 没有@Query注解,默认走实体类的字段 EQ精确 查询; - if (Objects.isNull(queryAnnotation)) { + if (null == 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)); - } - } - }); + final int columnLength = ArrayUtil.length(columns); + if (columnLength == 0 || columnLength == 1) { + columnName = columnLength == 1 ? columns[0] : columnName; + parse(queryAnnotation.type(), columnName, fieldValue, queryWrapper); return; } - // 解析查询条件 - parse(queryAnnotation.type(), columnName, fieldValue, queryWrapper); + // 解析多列查询 + QueryType queryType = queryAnnotation.type(); + queryWrapper.nested(wrapper -> { + for (String column : columns) { + switch (queryType) { + case EQ -> queryWrapper.or().eq(column, fieldValue); + case NE -> queryWrapper.or().ne(column, fieldValue); + case GT -> queryWrapper.or().gt(column, fieldValue); + case GE -> queryWrapper.or().ge(column, fieldValue); + case LT -> queryWrapper.or().lt(column, fieldValue); + case LE -> queryWrapper.or().le(column, fieldValue); + case BETWEEN -> { + List between = new ArrayList<>((List)fieldValue); + ValidationUtils.throwIf(between.size() != 2, "[{}] 必须是一个范围", fieldName); + queryWrapper.or().between(column, between.get(0), between.get(1)); + } + case LIKE -> queryWrapper.or().like(column, fieldValue); + case LIKE_LEFT -> queryWrapper.or().likeLeft(column, fieldValue); + case LIKE_RIGHT -> queryWrapper.or().likeRight(column, fieldValue); + case IN -> { + ValidationUtils.throwIfEmpty(fieldValue, "[{}] 不能为空", fieldName); + queryWrapper.or().in(column, (List)fieldValue); + } + case NOT_IN -> { + ValidationUtils.throwIfEmpty(fieldValue, "[{}] 不能为空", fieldName); + queryWrapper.or().notIn(column, (List)fieldValue); + } + case IS_NULL -> queryWrapper.or().isNull(column); + case IS_NOT_NULL -> queryWrapper.or().isNotNull(column); + default -> throw new IllegalArgumentException(String.format("暂不支持 [%s] 查询类型", queryType)); + } + } + }); } catch (BadRequestException e) { log.error("Build query occurred an validation error: {}. Query: {}, Field: {}.", e .getMessage(), query, field, e); @@ -155,30 +148,28 @@ public class QueryHelper { * @param queryType 查询类型 * @param columnName 驼峰字段名 * @param fieldValue 字段值 - * @param queryWrapper MyBatis Plus 查询条件封装对象 + * @param queryWrapper 查询条件封装对象 * @param 查询数据类型 */ private static void parse(QueryType queryType, String columnName, Object fieldValue, QueryWrapper queryWrapper) { - // 解析单个属性查询 - // 注意:数据库规范中列采用下划线连接法命名,程序规范中变量采用驼峰法命名 switch (queryType) { - case EQUAL -> queryWrapper.eq(columnName, fieldValue); - case NOT_EQUAL -> queryWrapper.ne(columnName, fieldValue); - case GREATER_THAN -> queryWrapper.gt(columnName, fieldValue); - case LESS_THAN -> queryWrapper.lt(columnName, fieldValue); - case GREATER_THAN_OR_EQUAL -> queryWrapper.ge(columnName, fieldValue); - case LESS_THAN_OR_EQUAL -> queryWrapper.le(columnName, fieldValue); + case EQ -> queryWrapper.eq(columnName, fieldValue); + case NE -> queryWrapper.ne(columnName, fieldValue); + case GT -> queryWrapper.gt(columnName, fieldValue); + case GE -> queryWrapper.ge(columnName, fieldValue); + case LT -> queryWrapper.lt(columnName, fieldValue); + case LE -> queryWrapper.le(columnName, fieldValue); case BETWEEN -> { List between = new ArrayList<>((List)fieldValue); 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 LIKE -> queryWrapper.like(columnName, fieldValue); + case LIKE_LEFT -> queryWrapper.likeLeft(columnName, fieldValue); + case LIKE_RIGHT -> queryWrapper.likeRight(columnName, fieldValue); case IN -> { ValidationUtils.throwIfEmpty(fieldValue, "[{}] 不能为空", columnName); queryWrapper.in(columnName, (List)fieldValue); diff --git a/continew-starter-data/continew-starter-data-mybatis-plus/src/main/java/top/charles7c/continew/starter/data/mybatis/plus/query/QueryType.java b/continew-starter-data/continew-starter-data-mybatis-plus/src/main/java/top/charles7c/continew/starter/data/mybatis/plus/query/QueryType.java index 75a1e5be..fe092b23 100644 --- a/continew-starter-data/continew-starter-data-mybatis-plus/src/main/java/top/charles7c/continew/starter/data/mybatis/plus/query/QueryType.java +++ b/continew-starter-data/continew-starter-data-mybatis-plus/src/main/java/top/charles7c/continew/starter/data/mybatis/plus/query/QueryType.java @@ -30,62 +30,72 @@ import lombok.RequiredArgsConstructor; public enum QueryType { /** - * 等值查询,例如:WHERE `age` = 18 + * 等于 =,例如:WHERE `age` = 18 */ - EQUAL(1, "="), + EQ, + /** - * 非等值查询,例如:WHERE `age` != 18 + * 不等于 !=,例如:WHERE `age` != 18 */ - NOT_EQUAL(2, "!="), + NE, + /** - * 大于查询,例如:WHERE `age` > 18 + * 大于 >,例如:WHERE `age` > 18 */ - GREATER_THAN(3, ">"), + GT, + /** - * 小于查询,例如:WHERE `age` < 18 + * 大于等于 >= ,例如:WHERE `age` >= 18 */ - LESS_THAN(4, "<"), + GE, + /** - * 大于等于查询,例如:WHERE `age` >= 18 + * 小于 <,例如:WHERE `age` < 18 */ - GREATER_THAN_OR_EQUAL(5, ">="), + LT, + /** - * 小于等于查询,例如:WHERE `age` <= 18 + * 小于等于 <=,例如:WHERE `age` <= 18 */ - LESS_THAN_OR_EQUAL(6, "<="), + LE, + /** * 范围查询,例如:WHERE `age` BETWEEN 10 AND 18 */ - BETWEEN(7, "BETWEEN"), + BETWEEN, + /** - * 左模糊查询,例如:WHERE `nickname` LIKE '%s' + * LIKE '%值%',例如:WHERE `nickname` LIKE '%s%' */ - LEFT_LIKE(8, "LIKE '%s'"), + LIKE, + /** - * 中模糊查询,例如:WHERE `nickname` LIKE '%s%' + * LIKE '%值',例如:WHERE `nickname` LIKE '%s' */ - INNER_LIKE(9, "LIKE '%s%'"), + LIKE_LEFT, + /** - * 右模糊查询,例如:WHERE `nickname` LIKE 's%' + * LIKE '值%',例如:WHERE `nickname` LIKE 's%' */ - RIGHT_LIKE(10, "LIKE 's%'"), + LIKE_RIGHT, + /** * 包含查询,例如:WHERE `age` IN (10, 20, 30) */ - IN(11, "IN"), + IN, + /** * 不包含查询,例如:WHERE `age` NOT IN (20, 30) */ - NOT_IN(12, "NOT IN"), + NOT_IN, + /** * 空查询,例如:WHERE `email` IS NULL */ - IS_NULL(13, "IS NULL"), + IS_NULL, + /** * 非空查询,例如:WHERE `email` IS NOT NULL */ - IS_NOT_NULL(14, "IS NOT NULL"),; - - private final Integer value; - private final String description; + IS_NOT_NULL,; } 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 fa0bd810..f9b43be6 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 @@ -51,7 +51,6 @@ import top.charles7c.continew.starter.file.excel.util.ExcelUtils; import java.io.Serializable; import java.lang.reflect.Field; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Optional; @@ -77,8 +76,8 @@ public abstract class BaseServiceImpl, T extends BaseDO, 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); + private final List entityFields = ReflectUtils.getNonStaticFields(this.entityClass); + private final List queryFields = ReflectUtils.getNonStaticFields(this.queryClass); @Override public PageResp page(Q query, PageQuery pageQuery) { @@ -193,46 +192,6 @@ public abstract class BaseServiceImpl, T extends BaseDO, return this.getById(id, true); } - /** - * 填充数据 - * - * @param obj 待填充信息 - */ - protected void fill(Object obj) { - if (null == obj) { - return; - } - OperateTemplate operateTemplate = SpringUtil.getBean(OperateTemplate.class); - operateTemplate.execute(obj); - } - - /** - * 设置排序 - * - * @param queryWrapper 查询 Wrapper - * @param sortQuery 排序查询条件 - */ - protected void sort(QueryWrapper queryWrapper, SortQuery sortQuery) { - Sort sort = Opt.ofNullable(sortQuery).orElseGet(SortQuery::new).getSort(); - for (Sort.Order order : sort) { - if (null != order) { - String property = order.getProperty(); - String checkProperty; - // 携带表别名,获取.后面的字段名 - if (property.contains(StringConstants.DOT)) { - checkProperty = CollectionUtil.getLast(StrUtil.split(property, StringConstants.DOT)); - } else { - checkProperty = property; - } - Optional optional = Arrays.stream(entityFields) - .filter(field -> checkProperty.equals(field.getName())) - .findFirst(); - ValidationUtils.throwIf(optional.isEmpty(), "无效的排序字段 [{}]。", property); - queryWrapper.orderBy(true, order.isAscending(), StrUtil.toUnderlineCase(property)); - } - } - } - /** * 根据 ID 查询 * @@ -249,9 +208,49 @@ public abstract class BaseServiceImpl, T extends BaseDO, } /** - * 获取当前详情信息类型 + * 设置排序 * - * @return 当前详情信息类型 + * @param queryWrapper 查询条件封装对象 + * @param sortQuery 排序查询条件 + */ + protected void sort(QueryWrapper queryWrapper, SortQuery sortQuery) { + Sort sort = Opt.ofNullable(sortQuery).orElseGet(SortQuery::new).getSort(); + for (Sort.Order order : sort) { + if (null != order) { + String property = order.getProperty(); + String checkProperty; + // 携带表别名则获取 . 后面的字段名 + if (property.contains(StringConstants.DOT)) { + checkProperty = CollectionUtil.getLast(StrUtil.split(property, StringConstants.DOT)); + } else { + checkProperty = property; + } + Optional optional = entityFields.stream() + .filter(field -> checkProperty.equals(field.getName())) + .findFirst(); + ValidationUtils.throwIf(optional.isEmpty(), "无效的排序字段 [{}]", property); + queryWrapper.orderBy(true, order.isAscending(), StrUtil.toUnderlineCase(property)); + } + } + } + + /** + * 填充数据 + * + * @param obj 待填充信息 + */ + protected void fill(Object obj) { + if (null == obj) { + return; + } + OperateTemplate operateTemplate = SpringUtil.getBean(OperateTemplate.class); + operateTemplate.execute(obj); + } + + /** + * 封装查询条件 + * + * @return 查询条件封装对象 */ protected QueryWrapper handleQueryWrapper(Q query) { QueryWrapper queryWrapper = new QueryWrapper<>(); @@ -259,8 +258,8 @@ public abstract class BaseServiceImpl, T extends BaseDO, if (null == query) { return queryWrapper; } - // 获取查询条件中所有的字段 - queryFields.forEach(field -> QueryHelper.buildQuery(query, field, queryWrapper)); + // 解析并拼接查询条件 + queryFields.forEach(field -> QueryHelper.buildWrapper(query, field, queryWrapper)); return queryWrapper; } @@ -343,9 +342,9 @@ public abstract class BaseServiceImpl, T extends BaseDO, } /** - * 获取当前查询类型 + * 获取当前查询条件类型 * - * @return 当前查询类型 + * @return 当前查询条件类型 */ protected Class currentQueryClass() { return (Class)this.typeArguments[4];