diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml
index 78a0ca658..99430571f 100644
--- a/yudao-dependencies/pom.xml
+++ b/yudao-dependencies/pom.xml
@@ -85,6 +85,7 @@
2.3.2
2.3.2
4.8.2-20260501.180637
+ 1.80
4.40.771.ALL
@@ -689,6 +690,24 @@
+
+
+ org.bouncycastle
+ bcprov-jdk18on
+ ${bouncycastle.version}
+
+
+ org.bouncycastle
+ bcutil-jdk18on
+ ${bouncycastle.version}
+
+
+ org.bouncycastle
+ bcpkix-jdk18on
+ ${bouncycastle.version}
+
+
com.github.binarywang
weixin-java-pay
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
index 8afabd9c5..a54adfbc3 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
@@ -100,6 +100,13 @@
com.fhs-opensource
easy-trans-mybatis-plus-extend
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java
index e9d400aaa..a23930187 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java
@@ -23,6 +23,7 @@ import net.sf.jsqlparser.schema.Table;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.regex.Pattern;
/**
* MyBatis 工具类
@@ -31,6 +32,8 @@ public class MyBatisUtils {
private static final String MYSQL_ESCAPE_CHARACTER = "`";
+ private static final Pattern SAFE_COLUMN_NAME_PATTERN = Pattern.compile("^[a-zA-Z0-9_]+(\\.[a-zA-Z0-9_]+)*$");
+
public static Page buildPage(PageParam pageParam) {
return buildPage(pageParam, null);
}
@@ -42,8 +45,11 @@ public class MyBatisUtils {
// 排序字段
if (CollUtil.isNotEmpty(sortingFields)) {
for (SortingField sortingField : sortingFields) {
- page.addOrder(new OrderItem().setAsc(SortingField.ORDER_ASC.equals(sortingField.getOrder()))
- .setColumn(StrUtil.toUnderlineCase(sortingField.getField())));
+ String columnName = buildSafeOrderColumn(sortingField.getField());
+ if (columnName == null) {
+ continue;
+ }
+ page.addOrder(new OrderItem().setAsc(isAscOrder(sortingField.getOrder())).setColumn(columnName));
}
}
return page;
@@ -57,23 +63,29 @@ public class MyBatisUtils {
if (wrapper instanceof QueryWrapper) {
QueryWrapper query = (QueryWrapper) wrapper;
for (SortingField sortingField : sortingFields) {
- query.orderBy(true,
- SortingField.ORDER_ASC.equals(sortingField.getOrder()),
- StrUtil.toUnderlineCase(sortingField.getField()));
+ String columnName = buildSafeOrderColumn(sortingField.getField());
+ if (columnName == null) {
+ continue;
+ }
+ query.orderBy(true, isAscOrder(sortingField.getOrder()), columnName);
}
} else if (wrapper instanceof LambdaQueryWrapper) {
// LambdaQueryWrapper 不直接支持字符串字段排序,使用 last 方法拼接 ORDER BY
LambdaQueryWrapper lambdaQuery = (LambdaQueryWrapper) wrapper;
StringBuilder orderBy = new StringBuilder();
for (SortingField sortingField : sortingFields) {
+ String columnName = buildSafeOrderColumn(sortingField.getField());
+ if (columnName == null) {
+ continue;
+ }
if (StrUtil.isNotEmpty(orderBy)) {
orderBy.append(", ");
}
- orderBy.append(StrUtil.toUnderlineCase(sortingField.getField()))
- .append(" ")
- .append(SortingField.ORDER_ASC.equals(sortingField.getOrder()) ? "ASC" : "DESC");
+ orderBy.append(columnName).append(" ").append(getOrderDirection(sortingField.getOrder()));
+ }
+ if (StrUtil.isNotEmpty(orderBy)) {
+ lambdaQuery.last("ORDER BY " + orderBy);
}
- lambdaQuery.last("ORDER BY " + orderBy);
// 另外个思路:https://blog.csdn.net/m0_59084856/article/details/138450913
} else {
throw new IllegalArgumentException("Unsupported wrapper type: " + wrapper.getClass().getName());
@@ -81,6 +93,22 @@ public class MyBatisUtils {
}
+ public static boolean isAscOrder(String order) {
+ return SortingField.ORDER_ASC.equals(order);
+ }
+
+ public static String getOrderDirection(String order) {
+ return isAscOrder(order) ? "ASC" : "DESC";
+ }
+
+ private static String buildSafeOrderColumn(String field) {
+ String columnName = StrUtil.toUnderlineCase(field);
+ if (StrUtil.isEmpty(columnName) || !SAFE_COLUMN_NAME_PATTERN.matcher(columnName).matches()) {
+ return null;
+ }
+ return columnName;
+ }
+
/**
* 将拦截器添加到链中
* 由于 MybatisPlusInterceptor 不支持添加拦截器,所以只能全量设置
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/test/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtilsTest.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/test/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtilsTest.java
new file mode 100644
index 000000000..43f5611dc
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/test/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtilsTest.java
@@ -0,0 +1,106 @@
+package cn.iocoder.yudao.framework.mybatis.core.util;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.SortingField;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.OrderItem;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * {@link MyBatisUtils} 的单元测试
+ */
+public class MyBatisUtilsTest {
+
+ @Test
+ public void testBuildPage_sortingFields() {
+ // 准备参数
+ PageParam pageParam = new PageParam();
+ pageParam.setPageNo(2);
+ pageParam.setPageSize(20);
+ List sortingFields = Arrays.asList(
+ new SortingField("userName", SortingField.ORDER_ASC),
+ new SortingField("u.id", SortingField.ORDER_DESC),
+ new SortingField("name desc", SortingField.ORDER_DESC));
+
+ // 调用
+ Page