From c31fa753b6d9753d72a2e28bf3184981ed848ac2 Mon Sep 17 00:00:00 2001 From: Charles7c Date: Tue, 13 Aug 2024 13:33:56 +0800 Subject: [PATCH] =?UTF-8?q?refactor(curd):=20=E9=87=8D=E6=9E=84=E6=8E=92?= =?UTF-8?q?=E5=BA=8F=E5=AD=97=E6=AE=B5=E5=A4=84=E7=90=86=EF=BC=8C=E9=A2=84?= =?UTF-8?q?=E9=98=B2=20SQL=20=E6=B3=A8=E5=85=A5=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../continew-starter-data-core/pom.xml | 5 + .../data/core/util/SqlInjectionUtils.java | 53 +++++++++ .../{query => util}/QueryWrapperHelper.java | 43 ++++++-- .../{query => util}/QueryWrapperHelper.java | 31 +++++- .../pom.xml | 18 ++-- .../extension/crud/model/query/PageQuery.java | 0 .../extension/crud/model/query/SortQuery.java | 27 +++-- .../crud/model/resp/BasePageResp.java | 73 +++++++++++++ .../extension/crud/model/resp/PageResp.java | 48 ++------- .../crud/service/impl/BaseServiceImpl.java | 11 +- .../extension/crud/model/query/PageQuery.java | 102 ------------------ .../extension/crud/model/resp/PageResp.java | 49 ++------- .../crud/service/impl/BaseServiceImpl.java | 47 ++++---- 13 files changed, 276 insertions(+), 231 deletions(-) create mode 100644 continew-starter-data/continew-starter-data-core/src/main/java/top/continew/starter/data/core/util/SqlInjectionUtils.java rename continew-starter-data/continew-starter-data-mybatis-flex/src/main/java/top/continew/starter/data/mybatis/flex/{query => util}/QueryWrapperHelper.java (86%) rename continew-starter-data/continew-starter-data-mybatis-plus/src/main/java/top/continew/starter/data/mybatis/plus/{query => util}/QueryWrapperHelper.java (89%) rename continew-starter-extension/continew-starter-extension-crud/{continew-starter-extension-crud-mf => continew-starter-extension-crud-core}/src/main/java/top/continew/starter/extension/crud/model/query/PageQuery.java (100%) create mode 100644 continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-core/src/main/java/top/continew/starter/extension/crud/model/resp/BasePageResp.java delete mode 100644 continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-mp/src/main/java/top/continew/starter/extension/crud/model/query/PageQuery.java diff --git a/continew-starter-data/continew-starter-data-core/pom.xml b/continew-starter-data/continew-starter-data-core/pom.xml index e48c7e15..73f5e3c5 100644 --- a/continew-starter-data/continew-starter-data-core/pom.xml +++ b/continew-starter-data/continew-starter-data-core/pom.xml @@ -18,5 +18,10 @@ cn.hutool hutool-db + + + org.springframework.data + spring-data-commons + \ No newline at end of file diff --git a/continew-starter-data/continew-starter-data-core/src/main/java/top/continew/starter/data/core/util/SqlInjectionUtils.java b/continew-starter-data/continew-starter-data-core/src/main/java/top/continew/starter/data/core/util/SqlInjectionUtils.java new file mode 100644 index 00000000..0a441550 --- /dev/null +++ b/continew-starter-data/continew-starter-data-core/src/main/java/top/continew/starter/data/core/util/SqlInjectionUtils.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + *

+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.starter.data.core.util; + +import java.util.Objects; +import java.util.regex.Pattern; + +/** + * SQL 注入验证工具类 + * + * @author hubin + * @since 2.5.2 + */ +public class SqlInjectionUtils { + + /** + * SQL语法检查正则:符合两个关键字(有先后顺序)才算匹配 + */ + private static final Pattern SQL_SYNTAX_PATTERN = Pattern + .compile("(insert|delete|update|select|create|drop|truncate|grant|alter|deny|revoke|call|execute|exec|declare|show|rename|set)" + "\\s+.*(into|from|set|where|table|database|view|index|on|cursor|procedure|trigger|for|password|union|and|or)|(select\\s*\\*\\s*from\\s+)|(and|or)\\s+.*", Pattern.CASE_INSENSITIVE); + + /** + * 使用'、;或注释截断SQL检查正则 + */ + private static final Pattern SQL_COMMENT_PATTERN = Pattern + .compile("'.*(or|union|--|#|/\\*|;)", Pattern.CASE_INSENSITIVE); + + /** + * 检查参数是否存在 SQL 注入 + * + * @param value 检查参数 + * @return true:非法;false:合法 + */ + public static boolean check(String value) { + Objects.requireNonNull(value); + // 处理是否包含 SQL 注释字符 || 检查是否包含 SQ L注入敏感字符 + return SQL_COMMENT_PATTERN.matcher(value).find() || SQL_SYNTAX_PATTERN.matcher(value).find(); + } +} \ No newline at end of file diff --git a/continew-starter-data/continew-starter-data-mybatis-flex/src/main/java/top/continew/starter/data/mybatis/flex/query/QueryWrapperHelper.java b/continew-starter-data/continew-starter-data-mybatis-flex/src/main/java/top/continew/starter/data/mybatis/flex/util/QueryWrapperHelper.java similarity index 86% rename from continew-starter-data/continew-starter-data-mybatis-flex/src/main/java/top/continew/starter/data/mybatis/flex/query/QueryWrapperHelper.java rename to continew-starter-data/continew-starter-data-mybatis-flex/src/main/java/top/continew/starter/data/mybatis/flex/util/QueryWrapperHelper.java index d286e119..ba0fcf68 100644 --- a/continew-starter-data/continew-starter-data-mybatis-flex/src/main/java/top/continew/starter/data/mybatis/flex/query/QueryWrapperHelper.java +++ b/continew-starter-data/continew-starter-data-mybatis-flex/src/main/java/top/continew/starter/data/mybatis/flex/util/QueryWrapperHelper.java @@ -14,21 +14,23 @@ * limitations under the License. */ -package top.continew.starter.data.mybatis.flex.query; +package top.continew.starter.data.mybatis.flex.util; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; import com.mybatisflex.core.query.QueryWrapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ArrayUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.text.CharSequenceUtil; +import org.springframework.data.domain.Sort; import top.continew.starter.core.exception.BadRequestException; import top.continew.starter.core.util.ReflectUtils; import top.continew.starter.core.util.validate.ValidationUtils; import top.continew.starter.data.core.annotation.Query; import top.continew.starter.data.core.annotation.QueryIgnore; import top.continew.starter.data.core.enums.QueryType; +import top.continew.starter.data.core.util.SqlInjectionUtils; import java.lang.reflect.Field; import java.util.ArrayList; @@ -56,10 +58,9 @@ public class QueryWrapperHelper { * * @param query 查询条件 * @param 查询条件数据类型 - * @param 查询数据类型 * @return QueryWrapper */ - public static QueryWrapper build(Q query) { + public static QueryWrapper build(Q query) { QueryWrapper queryWrapper = QueryWrapper.create(); // 没有查询条件,直接返回 if (null == query) { @@ -70,6 +71,34 @@ public class QueryWrapperHelper { return build(query, fieldList, queryWrapper); } + /** + * 构建 QueryWrapper + * + * @param query 查询条件 + * @param sort 排序条件 + * @param 查询条件数据类型 + * @return QueryWrapper + * @since 2.5.2 + */ + public static QueryWrapper build(Q query, Sort sort) { + QueryWrapper queryWrapper = QueryWrapper.create(); + // 没有查询条件,直接返回 + if (null == query) { + return queryWrapper; + } + // 设置排序条件 + if (sort != null && sort.isSorted()) { + for (Sort.Order order : sort) { + String field = CharSequenceUtil.toUnderlineCase(order.getProperty()); + ValidationUtils.throwIf(SqlInjectionUtils.check(field), "排序字段包含非法字符"); + queryWrapper.orderBy(field, order.isAscending()); + } + } + // 获取查询条件中所有的字段 + List fieldList = ReflectUtils.getNonStaticFields(query.getClass()); + return build(query, fieldList, queryWrapper); + } + /** * 构建 QueryWrapper * diff --git a/continew-starter-data/continew-starter-data-mybatis-plus/src/main/java/top/continew/starter/data/mybatis/plus/query/QueryWrapperHelper.java b/continew-starter-data/continew-starter-data-mybatis-plus/src/main/java/top/continew/starter/data/mybatis/plus/util/QueryWrapperHelper.java similarity index 89% rename from continew-starter-data/continew-starter-data-mybatis-plus/src/main/java/top/continew/starter/data/mybatis/plus/query/QueryWrapperHelper.java rename to continew-starter-data/continew-starter-data-mybatis-plus/src/main/java/top/continew/starter/data/mybatis/plus/util/QueryWrapperHelper.java index c79cbf10..fbe48ed7 100644 --- a/continew-starter-data/continew-starter-data-mybatis-plus/src/main/java/top/continew/starter/data/mybatis/plus/query/QueryWrapperHelper.java +++ b/continew-starter-data/continew-starter-data-mybatis-plus/src/main/java/top/continew/starter/data/mybatis/plus/util/QueryWrapperHelper.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package top.continew.starter.data.mybatis.plus.query; +package top.continew.starter.data.mybatis.plus.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,18 +23,17 @@ import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.text.CharSequenceUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.springframework.data.domain.Sort; import top.continew.starter.core.exception.BadRequestException; import top.continew.starter.core.util.ReflectUtils; import top.continew.starter.core.util.validate.ValidationUtils; import top.continew.starter.data.core.annotation.Query; import top.continew.starter.data.core.annotation.QueryIgnore; import top.continew.starter.data.core.enums.QueryType; +import top.continew.starter.data.core.util.SqlInjectionUtils; import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.util.*; import java.util.function.Consumer; /** @@ -60,11 +59,33 @@ public class QueryWrapperHelper { * @return QueryWrapper */ public static QueryWrapper build(Q query) { + return build(query, Sort.unsorted()); + } + + /** + * 构建 QueryWrapper + * + * @param query 查询条件 + * @param sort 排序条件 + * @param 查询条件数据类型 + * @param 查询数据类型 + * @return QueryWrapper + * @since 2.5.2 + */ + public static QueryWrapper build(Q query, Sort sort) { QueryWrapper queryWrapper = new QueryWrapper<>(); // 没有查询条件,直接返回 if (null == query) { return queryWrapper; } + // 设置排序条件 + if (sort != null && sort.isSorted()) { + for (Sort.Order order : sort) { + String field = CharSequenceUtil.toUnderlineCase(order.getProperty()); + ValidationUtils.throwIf(SqlInjectionUtils.check(field), "排序字段包含非法字符"); + queryWrapper.orderBy(true, order.isAscending(), field); + } + } // 获取查询条件中所有的字段 List fieldList = ReflectUtils.getNonStaticFields(query.getClass()); return build(query, fieldList, queryWrapper); diff --git a/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-core/pom.xml b/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-core/pom.xml index 3fe0c7d7..a0cc9d88 100644 --- a/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-core/pom.xml +++ b/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-core/pom.xml @@ -24,6 +24,12 @@ spring-data-commons + + + top.continew + continew-starter-web + + top.continew @@ -36,16 +42,16 @@ + + + top.continew + continew-starter-data-core + + top.continew continew-starter-file-excel - - - - top.continew - continew-starter-web - \ No newline at end of file diff --git a/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-mf/src/main/java/top/continew/starter/extension/crud/model/query/PageQuery.java b/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-core/src/main/java/top/continew/starter/extension/crud/model/query/PageQuery.java similarity index 100% rename from continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-mf/src/main/java/top/continew/starter/extension/crud/model/query/PageQuery.java rename to continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-core/src/main/java/top/continew/starter/extension/crud/model/query/PageQuery.java diff --git a/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-core/src/main/java/top/continew/starter/extension/crud/model/query/SortQuery.java b/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-core/src/main/java/top/continew/starter/extension/crud/model/query/SortQuery.java index 8d4683ea..aef5ce7e 100644 --- a/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-core/src/main/java/top/continew/starter/extension/crud/model/query/SortQuery.java +++ b/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-core/src/main/java/top/continew/starter/extension/crud/model/query/SortQuery.java @@ -16,14 +16,18 @@ package top.continew.starter.extension.crud.model.query; +import cn.hutool.core.net.URLDecoder; import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.util.ArrayUtil; import io.swagger.v3.oas.annotations.media.Schema; import org.springframework.data.domain.Sort; import top.continew.starter.core.constant.StringConstants; +import top.continew.starter.core.util.validate.ValidationUtils; +import top.continew.starter.data.core.util.SqlInjectionUtils; import java.io.Serial; import java.io.Serializable; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; @@ -54,20 +58,17 @@ public class SortQuery implements Serializable { if (ArrayUtil.isEmpty(sort)) { return Sort.unsorted(); } - + ValidationUtils.throwIf(sort.length < 2, "排序条件非法"); List orders = new ArrayList<>(sort.length); - if (CharSequenceUtil.contains(sort[0], StringConstants.COMMA)) { + if (CharSequenceUtil.contains(sort[0], URLDecoder.decode(StringConstants.COMMA, StandardCharsets.UTF_8))) { // e.g "sort=createTime,desc&sort=name,asc" for (String s : sort) { List sortList = CharSequenceUtil.splitTrim(s, StringConstants.COMMA); - Sort.Order order = new Sort.Order(Sort.Direction.valueOf(sortList.get(1).toUpperCase()), sortList - .get(0)); - orders.add(order); + orders.add(this.getOrder(sortList.get(0), sortList.get(1))); } } else { // e.g "sort=createTime,desc" - Sort.Order order = new Sort.Order(Sort.Direction.valueOf(sort[1].toUpperCase()), sort[0]); - orders.add(order); + orders.add(this.getOrder(sort[0], sort[1])); } return Sort.by(orders); } @@ -75,4 +76,16 @@ public class SortQuery implements Serializable { public void setSort(String[] sort) { this.sort = sort; } + + /** + * 获取排序条件 + * + * @param field 字段 + * @param direction 排序方向 + * @return 排序条件 + */ + private Sort.Order getOrder(String field, String direction) { + ValidationUtils.throwIf(SqlInjectionUtils.check(field), "排序字段包含非法字符"); + return new Sort.Order(Sort.Direction.valueOf(direction.toUpperCase()), field); + } } diff --git a/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-core/src/main/java/top/continew/starter/extension/crud/model/resp/BasePageResp.java b/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-core/src/main/java/top/continew/starter/extension/crud/model/resp/BasePageResp.java new file mode 100644 index 00000000..3b731a69 --- /dev/null +++ b/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-core/src/main/java/top/continew/starter/extension/crud/model/resp/BasePageResp.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + *

+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.continew.starter.extension.crud.model.resp; + +import io.swagger.v3.oas.annotations.media.Schema; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 分页信息 + * + * @param 列表数据类型 + * @author Charles7c + * @since 2.5.2 + */ +@Schema(description = "分页信息") +public class BasePageResp implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 列表数据 + */ + @Schema(description = "列表数据") + private List list; + + /** + * 总记录数 + */ + @Schema(description = "总记录数", example = "10") + private long total; + + public BasePageResp() { + } + + public BasePageResp(final List list, final long total) { + this.list = list; + this.total = total; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + public long getTotal() { + return total; + } + + public void setTotal(long total) { + this.total = total; + } +} diff --git a/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-mf/src/main/java/top/continew/starter/extension/crud/model/resp/PageResp.java b/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-mf/src/main/java/top/continew/starter/extension/crud/model/resp/PageResp.java index ece21115..552057c4 100644 --- a/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-mf/src/main/java/top/continew/starter/extension/crud/model/resp/PageResp.java +++ b/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-mf/src/main/java/top/continew/starter/extension/crud/model/resp/PageResp.java @@ -22,7 +22,6 @@ import com.mybatisflex.core.paginate.Page; import io.swagger.v3.oas.annotations.media.Schema; import java.io.Serial; -import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -35,22 +34,17 @@ import java.util.List; * @since 1.0.0 */ @Schema(description = "分页信息") -public class PageResp implements Serializable { +public class PageResp extends BasePageResp { @Serial private static final long serialVersionUID = 1L; - /** - * 列表数据 - */ - @Schema(description = "列表数据") - private List list; + public PageResp() { + } - /** - * 总记录数 - */ - @Schema(description = "总记录数", example = "10") - private long total; + public PageResp(final List list, final long total) { + super(list, total); + } /** * 基于 MyBatis Plus 分页数据构建分页信息,并将源数据转换为指定类型数据 @@ -65,10 +59,7 @@ public class PageResp implements Serializable { if (null == page) { return empty(); } - PageResp pageResp = new PageResp<>(); - pageResp.setList(BeanUtil.copyToList(page.getRecords(), targetClass)); - pageResp.setTotal(page.getTotalRow()); - return pageResp; + return new PageResp<>(BeanUtil.copyToList(page.getRecords(), targetClass), page.getTotalRow()); } /** @@ -82,10 +73,7 @@ public class PageResp implements Serializable { if (null == page) { return empty(); } - PageResp pageResp = new PageResp<>(); - pageResp.setList(page.getRecords()); - pageResp.setTotal(page.getTotalRow()); - return pageResp; + return new PageResp<>(page.getRecords(), page.getTotalRow()); } /** @@ -123,24 +111,6 @@ public class PageResp implements Serializable { * @return 分页信息 */ private static PageResp empty() { - PageResp pageResp = new PageResp<>(); - pageResp.setList(Collections.emptyList()); - return pageResp; - } - - public List getList() { - return list; - } - - public void setList(List list) { - this.list = list; - } - - public long getTotal() { - return total; - } - - public void setTotal(long total) { - this.total = total; + return new PageResp<>(Collections.emptyList(), 0L); } } diff --git a/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-mf/src/main/java/top/continew/starter/extension/crud/service/impl/BaseServiceImpl.java b/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-mf/src/main/java/top/continew/starter/extension/crud/service/impl/BaseServiceImpl.java index ce4bbc9c..c1f3cf16 100644 --- a/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-mf/src/main/java/top/continew/starter/extension/crud/service/impl/BaseServiceImpl.java +++ b/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-mf/src/main/java/top/continew/starter/extension/crud/service/impl/BaseServiceImpl.java @@ -35,7 +35,7 @@ import top.continew.starter.core.constant.StringConstants; import top.continew.starter.core.util.ReflectUtils; import top.continew.starter.core.util.validate.ValidationUtils; import top.continew.starter.data.mybatis.flex.base.BaseMapper; -import top.continew.starter.data.mybatis.flex.query.QueryWrapperHelper; +import top.continew.starter.data.mybatis.flex.util.QueryWrapperHelper; import top.continew.starter.data.mybatis.flex.service.impl.ServiceImpl; import top.continew.starter.extension.crud.annotation.TreeField; import top.continew.starter.extension.crud.model.query.PageQuery; @@ -73,6 +73,7 @@ public abstract class BaseServiceImpl, T extends BaseIdD @Override public PageResp page(Q query, PageQuery pageQuery) { QueryWrapper queryWrapper = this.buildQueryWrapper(query); + this.sort(queryWrapper, pageQuery); Page page = mapper.paginate(pageQuery.getPage(), pageQuery.getSize(), queryWrapper); PageResp pageResp = PageResp.build(page, listClass); pageResp.getList().forEach(this::fill); @@ -185,12 +186,12 @@ public abstract class BaseServiceImpl, T extends BaseIdD * @param sortQuery 排序查询条件 */ protected void sort(QueryWrapper queryWrapper, SortQuery sortQuery) { - Sort sort = Opt.ofNullable(sortQuery).orElseGet(SortQuery::new).getSort(); + if (sortQuery == null || sortQuery.getSort().isUnsorted()) { + return; + } + Sort sort = sortQuery.getSort(); List entityFields = ReflectUtils.getNonStaticFields(this.entityClass); for (Sort.Order order : sort) { - if (null == order) { - continue; - } String property = order.getProperty(); String checkProperty; // 携带表别名则获取 . 后面的字段名 diff --git a/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-mp/src/main/java/top/continew/starter/extension/crud/model/query/PageQuery.java b/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-mp/src/main/java/top/continew/starter/extension/crud/model/query/PageQuery.java deleted file mode 100644 index 563c95ce..00000000 --- a/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-mp/src/main/java/top/continew/starter/extension/crud/model/query/PageQuery.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. - *

- * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.gnu.org/licenses/lgpl.html - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package top.continew.starter.extension.crud.model.query; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.text.CharSequenceUtil; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.core.metadata.OrderItem; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.Min; -import org.hibernate.validator.constraints.Range; -import org.springdoc.core.annotations.ParameterObject; -import org.springframework.data.domain.Sort; - -import java.io.Serial; - -/** - * 分页查询条件 - * - * @author Charles7c - * @since 1.0.0 - */ -@ParameterObject -@Schema(description = "分页查询条件") -public class PageQuery extends SortQuery { - - @Serial - private static final long serialVersionUID = 1L; - /** - * 默认页码:1 - */ - private static final int DEFAULT_PAGE = 1; - /** - * 默认每页条数:10 - */ - private static final int DEFAULT_SIZE = 10; - - /** - * 页码 - */ - @Schema(description = "页码", example = "1") - @Min(value = 1, message = "页码最小值为 {value}") - private Integer page = DEFAULT_PAGE; - - /** - * 每页条数 - */ - @Schema(description = "每页条数", example = "10") - @Range(min = 1, max = 1000, message = "每页条数(取值范围 {min}-{max})") - private Integer size = DEFAULT_SIZE; - - /** - * 基于分页查询条件转换为 MyBatis Plus 分页条件 - * - * @param 列表数据类型 - * @return MyBatis Plus 分页条件 - */ - public IPage toPage() { - Page mybatisPage = new Page<>(this.getPage(), this.getSize()); - Sort pageSort = this.getSort(); - if (CollUtil.isNotEmpty(pageSort)) { - for (Sort.Order order : pageSort) { - OrderItem orderItem = new OrderItem(); - orderItem.setAsc(order.isAscending()); - orderItem.setColumn(CharSequenceUtil.toUnderlineCase(order.getProperty())); - mybatisPage.addOrder(orderItem); - } - } - return mybatisPage; - } - - public Integer getPage() { - return page; - } - - public void setPage(Integer page) { - this.page = page; - } - - public Integer getSize() { - return size; - } - - public void setSize(Integer size) { - this.size = size; - } -} diff --git a/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-mp/src/main/java/top/continew/starter/extension/crud/model/resp/PageResp.java b/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-mp/src/main/java/top/continew/starter/extension/crud/model/resp/PageResp.java index ade02623..8483bf7b 100644 --- a/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-mp/src/main/java/top/continew/starter/extension/crud/model/resp/PageResp.java +++ b/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-mp/src/main/java/top/continew/starter/extension/crud/model/resp/PageResp.java @@ -22,8 +22,8 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import io.swagger.v3.oas.annotations.media.Schema; import java.io.Serial; -import java.io.Serializable; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -34,22 +34,17 @@ import java.util.List; * @since 1.0.0 */ @Schema(description = "分页信息") -public class PageResp implements Serializable { +public class PageResp extends BasePageResp { @Serial private static final long serialVersionUID = 1L; - /** - * 列表数据 - */ - @Schema(description = "列表数据") - private List list; + public PageResp() { + } - /** - * 总记录数 - */ - @Schema(description = "总记录数", example = "10") - private long total; + public PageResp(final List list, final long total) { + super(list, total); + } /** * 基于 MyBatis Plus 分页数据构建分页信息,并将源数据转换为指定类型数据 @@ -64,10 +59,7 @@ public class PageResp implements Serializable { if (null == page) { return empty(); } - PageResp pageResp = new PageResp<>(); - pageResp.setList(BeanUtil.copyToList(page.getRecords(), targetClass)); - pageResp.setTotal(page.getTotal()); - return pageResp; + return new PageResp<>(BeanUtil.copyToList(page.getRecords(), targetClass), page.getTotal()); } /** @@ -81,10 +73,7 @@ public class PageResp implements Serializable { if (null == page) { return empty(); } - PageResp pageResp = new PageResp<>(); - pageResp.setList(page.getRecords()); - pageResp.setTotal(page.getTotal()); - return pageResp; + return new PageResp<>(page.getRecords(), page.getTotal()); } /** @@ -122,24 +111,6 @@ public class PageResp implements Serializable { * @return 分页信息 */ private static PageResp empty() { - PageResp pageResp = new PageResp<>(); - pageResp.setList(new ArrayList<>(0)); - return pageResp; - } - - public List getList() { - return list; - } - - public void setList(List list) { - this.list = list; - } - - public long getTotal() { - return total; - } - - public void setTotal(long total) { - this.total = total; + return new PageResp<>(Collections.emptyList(), 0L); } } diff --git a/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-mp/src/main/java/top/continew/starter/extension/crud/service/impl/BaseServiceImpl.java b/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-mp/src/main/java/top/continew/starter/extension/crud/service/impl/BaseServiceImpl.java index 3ace52b1..9e955632 100644 --- a/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-mp/src/main/java/top/continew/starter/extension/crud/service/impl/BaseServiceImpl.java +++ b/continew-starter-extension/continew-starter-extension-crud/continew-starter-extension-crud-mp/src/main/java/top/continew/starter/extension/crud/service/impl/BaseServiceImpl.java @@ -20,15 +20,15 @@ import cn.crane4j.core.support.OperateTemplate; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.copier.CopyOptions; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.lang.Opt; import cn.hutool.core.lang.tree.Tree; import cn.hutool.core.lang.tree.TreeNodeConfig; import cn.hutool.core.map.MapUtil; -import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.core.util.ReflectUtil; import cn.hutool.extra.spring.SpringUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import jakarta.servlet.http.HttpServletResponse; import org.springframework.data.domain.Sort; import org.springframework.transaction.annotation.Transactional; @@ -38,21 +38,24 @@ import top.continew.starter.core.util.ReflectUtils; import top.continew.starter.core.util.validate.CheckUtils; import top.continew.starter.core.util.validate.ValidationUtils; import top.continew.starter.data.mybatis.plus.base.BaseMapper; -import top.continew.starter.data.mybatis.plus.query.QueryWrapperHelper; import top.continew.starter.data.mybatis.plus.service.impl.ServiceImpl; +import top.continew.starter.data.mybatis.plus.util.QueryWrapperHelper; import top.continew.starter.extension.crud.annotation.DictField; import top.continew.starter.extension.crud.annotation.TreeField; import top.continew.starter.extension.crud.model.entity.BaseIdDO; +import top.continew.starter.extension.crud.model.query.PageQuery; import top.continew.starter.extension.crud.model.query.SortQuery; import top.continew.starter.extension.crud.model.resp.LabelValueResp; import top.continew.starter.extension.crud.model.resp.PageResp; import top.continew.starter.extension.crud.service.BaseService; import top.continew.starter.extension.crud.util.TreeUtils; -import top.continew.starter.extension.crud.model.query.PageQuery; import top.continew.starter.file.excel.util.ExcelUtils; import java.lang.reflect.Field; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; /** * 业务实现基类 @@ -76,7 +79,8 @@ public abstract class BaseServiceImpl, T extends BaseIdD @Override public PageResp page(Q query, PageQuery pageQuery) { QueryWrapper queryWrapper = this.buildQueryWrapper(query); - IPage page = baseMapper.selectPage(pageQuery.toPage(), queryWrapper); + this.sort(queryWrapper, pageQuery); + IPage page = baseMapper.selectPage(new Page<>(pageQuery.getPage(), pageQuery.getSize()), queryWrapper); PageResp pageResp = PageResp.build(page, this.getListClass()); pageResp.getList().forEach(this::fill); return pageResp; @@ -253,23 +257,24 @@ public abstract class BaseServiceImpl, T extends BaseIdD * @param sortQuery 排序查询条件 */ protected void sort(QueryWrapper queryWrapper, SortQuery sortQuery) { - Sort sort = Opt.ofNullable(sortQuery).orElseGet(SortQuery::new).getSort(); + if (sortQuery == null || sortQuery.getSort().isUnsorted()) { + return; + } + Sort sort = sortQuery.getSort(); for (Sort.Order order : sort) { - if (null != order) { - String property = order.getProperty(); - String checkProperty; - // 携带表别名则获取 . 后面的字段名 - if (property.contains(StringConstants.DOT)) { - checkProperty = CollUtil.getLast(CharSequenceUtil.split(property, StringConstants.DOT)); - } else { - checkProperty = property; - } - Optional optional = super.getEntityFields().stream() - .filter(field -> checkProperty.equals(field.getName())) - .findFirst(); - ValidationUtils.throwIf(optional.isEmpty(), "无效的排序字段 [{}]", property); - queryWrapper.orderBy(true, order.isAscending(), CharSequenceUtil.toUnderlineCase(property)); + String property = order.getProperty(); + String checkProperty; + // 携带表别名则获取 . 后面的字段名 + if (property.contains(StringConstants.DOT)) { + checkProperty = CollUtil.getLast(CharSequenceUtil.split(property, StringConstants.DOT)); + } else { + checkProperty = property; } + Optional optional = super.getEntityFields().stream() + .filter(field -> checkProperty.equals(field.getName())) + .findFirst(); + ValidationUtils.throwIf(optional.isEmpty(), "无效的排序字段 [{}]", property); + queryWrapper.orderBy(true, order.isAscending(), CharSequenceUtil.toUnderlineCase(property)); } }