소스 검색

dpp推送

ZhuDeKang 4 달 전
부모
커밋
5f7394c020

+ 3 - 0
ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java

@@ -1,6 +1,7 @@
 package com.ruoyi;
 
 import com.aizuda.snailjob.client.starter.EnableSnailJob;
+import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
@@ -12,6 +13,8 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
  */
 @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
 @EnableSnailJob
+
+@MapperScan("com.ruoyi.**.mapper")
 public class RuoYiApplication
 {
     public static void main(String[] args)

+ 13 - 0
ruoyi-admin/src/main/resources/application.yml

@@ -98,6 +98,17 @@ mybatis-plus:
       logic-delete-value: 9 # 逻辑已删除值(默认为 1)
       logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
 
+mybatis-plus-join:
+  # 是否打印 mybatis plus join banner,默认true
+  banner: false
+  # 全局启用副表逻辑删除,默认true。关闭后关联查询不会加副表逻辑删除
+  sub-table-logic: true
+  # 拦截器MappedStatement缓存,默认 true
+  ms-cache: true
+  # 表别名(默认 t)
+  table-alias: t
+  # 副表逻辑删除条件的位置,支持 WHERE、ON,默认 ON
+  logic-del-type: on
 # PageHelper分页插件
 pagehelper:
   #helperDialect: mysql
@@ -179,3 +190,5 @@ ds:
 id.workerId: 1
 #数据中心ID(0~31)
 id.datacenterId: 1
+
+

+ 25 - 0
ruoyi-admin/src/main/resources/kms_client.yml

@@ -0,0 +1,25 @@
+# 服务地址 格式 ip:port
+address: 10.0.249.142:19190
+## 以下两项使用kcsp平台的kms必填,均由kcsp平台提供。非kcsp平台可为空
+#contextPath: /KMSapi/kcspKMSv1RSFFkoal
+#kid: 166086164895733350518985b591e713
+#以下两项必填(由kms aksk 管理解密生成)
+accessKey: scj2D1OC4EqnnHYf
+secretKey: ZNdERcfhEoFJuSlI
+
+#是否使用tls
+useTLS: false
+#本地信任keyStore路径
+trustStorePath: trustStore.jks
+#本地信任keyStore密码
+trustStorePassword: KeyStorePassword
+#本地keyStore路径
+keyStorePath: keyStore.jks
+#本地keyStore密码
+keyStorePassword: KeyStorePassword
+#本地keyStore中key的密码
+keyPassword:
+#useRsa: false
+
+pooling:
+  testOnBorrow: true

+ 185 - 342
ruoyi-admin/src/test/java/com/ruoyi/JasyptTest.java

@@ -1,356 +1,199 @@
 package com.ruoyi;
 
-import com.agentsflex.chain.node.JsExecNode;
-import com.agentsflex.core.chain.Chain;
-import org.jasypt.encryption.StringEncryptor;
-import org.junit.jupiter.api.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import com.ruoyi.model.dpp.dal.dataobject.etl.DppEtlTaskDO;
+import com.ruoyi.model.etl.mapper.DppEtlTaskMapper;
+import com.ruoyi.model.etl.mapper.TestDppEtlTaskMapper;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.TestPropertySource;
+import org.springframework.context.ApplicationContext;
+import org.springframework.test.context.junit4.SpringRunner;
 
-import java.util.Date;
-import java.util.HashMap;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Map;
 
-@SpringBootTest(classes = RuoYiApplication.class)
-@TestPropertySource(properties = {"spring.profiles.active=druid"})
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+
+@SpringBootTest(classes = RuoYiApplication.class,webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@RunWith(SpringRunner.class)
 public class JasyptTest {
-    private static final Logger log = LoggerFactory.getLogger(JasyptTest.class);
+
+
+    @Test
+    public void comprehensiveDiagnosis() {
+        System.out.println("=== 全面诊断 MyBatis-Plus Join 问题 ===");
+
+        // 1. 检查上下文
+        assertNotNull(applicationContext);
+
+        // 2. 检查 Mapper 注入
+        assertNotNull(dppEtlTaskMapper);
+        System.out.println("✅ Mapper 注入成功");
+
+        // 3. 检查 BaseMapperX 继承
+        testBaseMapperXInheritance();
+
+        // 4. 检查 MyBatis-Plus Join 配置
+        checkMyBatisPlusJoinAutoConfiguration();
+
+        // 5. 测试其他 MPJ 方法(如果 selectJoinPage 不行)
+        testOtherMPJMethods();
+    }
+
+    private void testOtherMPJMethods() {
+        System.out.println("=== 测试其他 MyBatis-Plus Join 方法 ===");
+
+        MPJLambdaWrapper<DppEtlTaskDO> wrapper = new MPJLambdaWrapper<>();
+        wrapper.eq(DppEtlTaskDO::getDelFlag, "0");
+
+        // 测试 selectJoinList
+        try {
+            List<DppEtlTaskDO> result = dppEtlTaskMapper.selectJoinList(DppEtlTaskDO.class, wrapper);
+            System.out.println("✅ selectJoinList 工作正常,结果数量: " + result.size());
+        } catch (Exception e) {
+            System.out.println("❌ selectJoinList 也失败: " + e.getMessage());
+        }
+
+        // 测试 selectJoinOne
+        try {
+            DppEtlTaskDO result = dppEtlTaskMapper.selectJoinOne(DppEtlTaskDO.class, wrapper);
+            System.out.println("✅ selectJoinOne 工作正常");
+        } catch (Exception e) {
+            System.out.println("❌ selectJoinOne 失败: " + e.getMessage());
+        }
+    }
+
+
+
+
+    @Test
+    public void checkMyBatisPlusJoinAutoConfiguration() {
+        System.out.println("=== 检查 MyBatis-Plus Join 自动配置 ===");
+
+        try {
+            // 检查 MPJInterceptor 是否存在
+            Object mpjInterceptor = applicationContext.getBean("mpjInterceptor");
+            System.out.println("✅ MPJInterceptor 存在: " + mpjInterceptor.getClass().getName());
+        } catch (Exception e) {
+            System.out.println("❌ MPJInterceptor 不存在: " + e.getMessage());
+        }
+
+        // 检查 MyBatis-Plus Join 相关的 Bean
+        String[] beanNames = applicationContext.getBeanNamesForType(com.github.yulichang.interceptor.MPJInterceptor.class);
+        System.out.println("找到的 MPJInterceptor Beans: " + Arrays.toString(beanNames));
+    }
+
+
+    @Test
+    public void testBaseMapperXInheritance() {
+        System.out.println("=== 验证 BaseMapperX 继承关系 ===");
+
+        // 检查 Mapper 的实际类型
+        Class<?> mapperClass = dppEtlTaskMapper.getClass();
+        System.out.println("Mapper 实际类: " + mapperClass.getName());
+
+        // 检查实现的接口
+        Class<?>[] interfaces = mapperClass.getInterfaces();
+        for (Class<?> iface : interfaces) {
+            System.out.println("实现的接口: " + iface.getName());
+        }
+
+        // 检查是否是 MPJBaseMapper 的实例
+        boolean isMPJBaseMapper = dppEtlTaskMapper instanceof com.github.yulichang.base.MPJBaseMapper;
+        System.out.println("是否是 MPJBaseMapper 实例: " + isMPJBaseMapper);
+
+        // 尝试通过反射查看方法
+        try {
+            java.lang.reflect.Method method = dppEtlTaskMapper.getClass().getMethod("selectJoinPage",
+                    com.baomidou.mybatisplus.core.metadata.IPage.class, Class.class, com.github.yulichang.wrapper.MPJLambdaWrapper.class);
+            System.out.println("找到 selectJoinPage 方法: " + method);
+        } catch (NoSuchMethodException e) {
+            System.out.println("未找到 selectJoinPage 方法");
+        }
+    }
+
+
+
+    @Autowired(required = false)  // 设置为非必需,避免启动失败
+    private TestDppEtlTaskMapper dppEtlTaskMapper;
+
     @Autowired
-    private StringEncryptor stringEncryptor;
+    private ApplicationContext applicationContext;
 
     @Test
-    public void encryptPwd() {
-
-        String code = "{\n" +
-                "    \"edges\": [\n" +
-                "        {\n" +
-                "            \"id\": \"g1MbfnZ5Gwb90H8H\",\n" +
-                "            \"source\": \"node_ncZomj9VYJSr3P3V\",\n" +
-                "            \"target\": \"node_6ajjEYlMDPcYl3ae\",\n" +
-                "            \"selected\": false\n" +
-                "        },\n" +
-                "        {\n" +
-                "            \"id\": \"jC3w6Thci7Ua8tFO\",\n" +
-                "            \"source\": \"U6DteBZHGQfaBvpP\",\n" +
-                "            \"target\": \"node_6ajjEYlMDPcYl3ae\",\n" +
-                "            \"selected\": false\n" +
-                "        },\n" +
-                "        {\n" +
-                "            \"id\": \"LY9hCUFEEqq0AoZl\",\n" +
-                "            \"source\": \"ucHhhciLB2U9snEM\",\n" +
-                "            \"target\": \"node_6ajjEYlMDPcYl3ae\",\n" +
-                "            \"selected\": false\n" +
-                "        },\n" +
-                "        {\n" +
-                "            \"id\": \"EIOzuvcuPaD4k9tb\",\n" +
-                "            \"source\": \"node_B3Lz55SHHuTTE3TC\",\n" +
-                "            \"target\": \"node_ncZomj9VYJSr3P3V\",\n" +
-                "            \"selected\": false\n" +
-                "        },\n" +
-                "        {\n" +
-                "            \"id\": \"t68rwPo1Q8UFcRZc\",\n" +
-                "            \"source\": \"node_1z5lKKFYhSYjDyKI\",\n" +
-                "            \"target\": \"node_B3Lz55SHHuTTE3TC\",\n" +
-                "            \"selected\": false\n" +
-                "        },\n" +
-                "        {\n" +
-                "            \"id\": \"M11hEF6ug1Wb79XB\",\n" +
-                "            \"source\": \"node_B3Lz55SHHuTTE3TC\",\n" +
-                "            \"target\": \"U6DteBZHGQfaBvpP\",\n" +
-                "            \"selected\": false\n" +
-                "        },\n" +
-                "        {\n" +
-                "            \"id\": \"6mL3Q2RAiHqiCkHm\",\n" +
-                "            \"source\": \"node_B3Lz55SHHuTTE3TC\",\n" +
-                "            \"target\": \"ucHhhciLB2U9snEM\",\n" +
-                "            \"selected\": false\n" +
-                "        },\n" +
-                "        {\n" +
-                "            \"id\": \"L8v1pqEBUdeqsk1e\",\n" +
-                "            \"source\": \"node_6ajjEYlMDPcYl3ae\",\n" +
-                "            \"target\": \"node_tciO7KE86u6PHgKr\"\n" +
-                "        },\n" +
-                "        {\n" +
-                "            \"id\": \"aO2ayu7f6CkuKs0r\",\n" +
-                "            \"source\": \"node_tciO7KE86u6PHgKr\",\n" +
-                "            \"target\": \"node_At2IIxQgEILAOu4n\"\n" +
-                "        }\n" +
-                "    ],\n" +
-                "    \"nodes\": [\n" +
-                "        {\n" +
-                "            \"id\": \"node_1z5lKKFYhSYjDyKI\",\n" +
-                "            \"data\": {\n" +
-                "                \"title\": \"开始节点\",\n" +
-                "                \"description\": \"开始定义输入参数\"\n" +
-                "            },\n" +
-                "            \"type\": \"startNode\",\n" +
-                "            \"dragging\": false,\n" +
-                "            \"measured\": {\n" +
-                "                \"width\": 306,\n" +
-                "                \"height\": 88\n" +
-                "            },\n" +
-                "            \"position\": {\n" +
-                "                \"x\": -547.0868680833916,\n" +
-                "                \"y\": 137.4465838737692\n" +
-                "            },\n" +
-                "            \"selected\": false\n" +
-                "        },\n" +
-                "        {\n" +
-                "            \"id\": \"node_ncZomj9VYJSr3P3V\",\n" +
-                "            \"data\": {\n" +
-                "                \"title\": \"获取雨量数据\",\n" +
-                "                \"expand\": false,\n" +
-                "                \"method\": \"get\",\n" +
-                "                \"outputDefs\": [\n" +
-                "                    {\n" +
-                "                        \"id\": \"1tTsWjENoLfB4JJa\",\n" +
-                "                        \"name\": \"headers\",\n" +
-                "                        \"refType\": \"ref\",\n" +
-                "                        \"dataType\": \"Object\",\n" +
-                "                        \"nameDisabled\": true,\n" +
-                "                        \"deleteDisabled\": true,\n" +
-                "                        \"dataTypeDisabled\": true\n" +
-                "                    },\n" +
-                "                    {\n" +
-                "                        \"id\": \"9OP5JjlkBqARboVZ\",\n" +
-                "                        \"name\": \"body\",\n" +
-                "                        \"refType\": \"ref\",\n" +
-                "                        \"dataType\": \"String\",\n" +
-                "                        \"nameDisabled\": true,\n" +
-                "                        \"deleteDisabled\": true\n" +
-                "                    },\n" +
-                "                    {\n" +
-                "                        \"id\": \"94bsldmZ4cbcx7Or\",\n" +
-                "                        \"name\": \"statusCode\",\n" +
-                "                        \"refType\": \"ref\",\n" +
-                "                        \"dataType\": \"Number\",\n" +
-                "                        \"nameDisabled\": true,\n" +
-                "                        \"deleteDisabled\": true,\n" +
-                "                        \"dataTypeDisabled\": true\n" +
-                "                    }\n" +
-                "                ],\n" +
-                "                \"parameters\": [\n" +
-                "                    {\n" +
-                "                        \"id\": \"xscx2BZ3xAx8FBdB\",\n" +
-                "                        \"name\": \"STCD\",\n" +
-                "                        \"refType\": \"ref\",\n" +
-                "                        \"dataType\": \"String\"\n" +
-                "                    },\n" +
-                "                    {\n" +
-                "                        \"id\": \"tvzDXYZDpPHuCm1b\",\n" +
-                "                        \"name\": \"\",\n" +
-                "                        \"refType\": \"ref\",\n" +
-                "                        \"dataType\": \"String\"\n" +
-                "                    },\n" +
-                "                    {\n" +
-                "                        \"id\": \"jGFiQp0F47cfUODL\",\n" +
-                "                        \"name\": \"\",\n" +
-                "                        \"refType\": \"ref\",\n" +
-                "                        \"dataType\": \"String\"\n" +
-                "                    }\n" +
-                "                ],\n" +
-                "                \"description\": \"通过 HTTP 请求获取数据\"\n" +
-                "            },\n" +
-                "            \"type\": \"httpNode\",\n" +
-                "            \"dragging\": false,\n" +
-                "            \"measured\": {\n" +
-                "                \"width\": 306,\n" +
-                "                \"height\": 88\n" +
-                "            },\n" +
-                "            \"position\": {\n" +
-                "                \"x\": 392.078125,\n" +
-                "                \"y\": 34.671875\n" +
-                "            },\n" +
-                "            \"selected\": false\n" +
-                "        },\n" +
-                "        {\n" +
-                "            \"id\": \"U6DteBZHGQfaBvpP\",\n" +
-                "            \"data\": {\n" +
-                "                \"title\": \"获取水位数据\",\n" +
-                "                \"expand\": false,\n" +
-                "                \"method\": \"get\",\n" +
-                "                \"outputDefs\": [\n" +
-                "                    {\n" +
-                "                        \"id\": \"1tTsWjENoLfB4JJa\",\n" +
-                "                        \"name\": \"headers\",\n" +
-                "                        \"refType\": \"ref\",\n" +
-                "                        \"dataType\": \"Object\",\n" +
-                "                        \"nameDisabled\": true,\n" +
-                "                        \"deleteDisabled\": true,\n" +
-                "                        \"dataTypeDisabled\": true\n" +
-                "                    },\n" +
-                "                    {\n" +
-                "                        \"id\": \"9OP5JjlkBqARboVZ\",\n" +
-                "                        \"name\": \"body\",\n" +
-                "                        \"refType\": \"ref\",\n" +
-                "                        \"dataType\": \"String\",\n" +
-                "                        \"nameDisabled\": true,\n" +
-                "                        \"deleteDisabled\": true\n" +
-                "                    },\n" +
-                "                    {\n" +
-                "                        \"id\": \"94bsldmZ4cbcx7Or\",\n" +
-                "                        \"name\": \"statusCode\",\n" +
-                "                        \"refType\": \"ref\",\n" +
-                "                        \"dataType\": \"Number\",\n" +
-                "                        \"nameDisabled\": true,\n" +
-                "                        \"deleteDisabled\": true,\n" +
-                "                        \"dataTypeDisabled\": true\n" +
-                "                    }\n" +
-                "                ],\n" +
-                "                \"description\": \"通过 HTTP 请求获取数据\"\n" +
-                "            },\n" +
-                "            \"type\": \"httpNode\",\n" +
-                "            \"dragging\": false,\n" +
-                "            \"measured\": {\n" +
-                "                \"width\": 306,\n" +
-                "                \"height\": 88\n" +
-                "            },\n" +
-                "            \"position\": {\n" +
-                "                \"x\": 390.078125,\n" +
-                "                \"y\": 154.671875\n" +
-                "            },\n" +
-                "            \"selected\": false\n" +
-                "        },\n" +
-                "        {\n" +
-                "            \"id\": \"ucHhhciLB2U9snEM\",\n" +
-                "            \"data\": {\n" +
-                "                \"title\": \"获取气象数据\",\n" +
-                "                \"method\": \"get\",\n" +
-                "                \"outputDefs\": [\n" +
-                "                    {\n" +
-                "                        \"id\": \"1tTsWjENoLfB4JJa\",\n" +
-                "                        \"name\": \"headers\",\n" +
-                "                        \"refType\": \"ref\",\n" +
-                "                        \"dataType\": \"Object\",\n" +
-                "                        \"nameDisabled\": true,\n" +
-                "                        \"deleteDisabled\": true,\n" +
-                "                        \"dataTypeDisabled\": true\n" +
-                "                    },\n" +
-                "                    {\n" +
-                "                        \"id\": \"9OP5JjlkBqARboVZ\",\n" +
-                "                        \"name\": \"body\",\n" +
-                "                        \"refType\": \"ref\",\n" +
-                "                        \"dataType\": \"String\",\n" +
-                "                        \"nameDisabled\": true,\n" +
-                "                        \"deleteDisabled\": true\n" +
-                "                    },\n" +
-                "                    {\n" +
-                "                        \"id\": \"94bsldmZ4cbcx7Or\",\n" +
-                "                        \"name\": \"statusCode\",\n" +
-                "                        \"refType\": \"ref\",\n" +
-                "                        \"dataType\": \"Number\",\n" +
-                "                        \"nameDisabled\": true,\n" +
-                "                        \"deleteDisabled\": true,\n" +
-                "                        \"dataTypeDisabled\": true\n" +
-                "                    }\n" +
-                "                ],\n" +
-                "                \"description\": \"通过 HTTP 请求获取数据\"\n" +
-                "            },\n" +
-                "            \"type\": \"httpNode\",\n" +
-                "            \"dragging\": false,\n" +
-                "            \"measured\": {\n" +
-                "                \"width\": 306,\n" +
-                "                \"height\": 88\n" +
-                "            },\n" +
-                "            \"position\": {\n" +
-                "                \"x\": 390.078125,\n" +
-                "                \"y\": 268.671875\n" +
-                "            },\n" +
-                "            \"selected\": false\n" +
-                "        },\n" +
-                "        {\n" +
-                "            \"id\": \"node_6ajjEYlMDPcYl3ae\",\n" +
-                "            \"data\": {\n" +
-                "                \"title\": \"模型计算\",\n" +
-                "                \"expand\": false\n" +
-                "            },\n" +
-                "            \"type\": \"task-node\",\n" +
-                "            \"dragging\": false,\n" +
-                "            \"measured\": {\n" +
-                "                \"width\": 306,\n" +
-                "                \"height\": 88\n" +
-                "            },\n" +
-                "            \"position\": {\n" +
-                "                \"x\": 866.148775304685,\n" +
-                "                \"y\": 134.94990664309157\n" +
-                "            },\n" +
-                "            \"selected\": false\n" +
-                "        },\n" +
-                "        {\n" +
-                "            \"id\": \"node_At2IIxQgEILAOu4n\",\n" +
-                "            \"data\": {\n" +
-                "                \"title\": \"图表节点\",\n" +
-                "                \"expand\": false\n" +
-                "            },\n" +
-                "            \"type\": \"chart-node\",\n" +
-                "            \"dragging\": false,\n" +
-                "            \"measured\": {\n" +
-                "                \"width\": 306,\n" +
-                "                \"height\": 88\n" +
-                "            },\n" +
-                "            \"position\": {\n" +
-                "                \"x\": 1707.2668779489672,\n" +
-                "                \"y\": 134.90843037541023\n" +
-                "            },\n" +
-                "            \"selected\": false\n" +
-                "        },\n" +
-                "        {\n" +
-                "            \"id\": \"node_B3Lz55SHHuTTE3TC\",\n" +
-                "            \"data\": {\n" +
-                "                \"title\": \"新建方案\"\n" +
-                "            },\n" +
-                "            \"type\": \"task-node\",\n" +
-                "            \"dragging\": false,\n" +
-                "            \"measured\": {\n" +
-                "                \"width\": 306,\n" +
-                "                \"height\": 88\n" +
-                "            },\n" +
-                "            \"position\": {\n" +
-                "                \"x\": -124.87829206235932,\n" +
-                "                \"y\": 142.06519629483878\n" +
-                "            },\n" +
-                "            \"selected\": false\n" +
-                "        },\n" +
-                "        {\n" +
-                "            \"id\": \"node_tciO7KE86u6PHgKr\",\n" +
-                "            \"data\": {\n" +
-                "                \"title\": \"输出结果\",\n" +
-                "                \"expand\": false\n" +
-                "            },\n" +
-                "            \"type\": \"task-node\",\n" +
-                "            \"dragging\": false,\n" +
-                "            \"measured\": {\n" +
-                "                \"width\": 306,\n" +
-                "                \"height\": 88\n" +
-                "            },\n" +
-                "            \"position\": {\n" +
-                "                \"x\": 1291.991164789477,\n" +
-                "                \"y\": 134.31405390092667\n" +
-                "            },\n" +
-                "            \"selected\": false\n" +
-                "        }\n" +
-                "    ],\n" +
-                "    \"viewport\": {\n" +
-                "        \"x\": 830.8418078373795,\n" +
-                "        \"y\": 130.69047266353977,\n" +
-                "        \"zoom\": 1.741101126592249\n" +
-                "    }\n" +
-                "}";
-
-        Chain chain = new Chain();
-
-        JsExecNode a = new JsExecNode();
-        a.setCode(code);
-        a.setId("a");
-//        a.setCode(code);
-        chain.addNode(a);
-
-        Map<String, Object> result = chain.executeForResult(new HashMap<>());
-        System.out.println(result.getClass());
-        System.out.println(result);
+    public void testMyBatisPlusJoinConfiguration() {
+        System.out.println("=== 开始诊断 Mapper 注入问题 ===");
+
+        // 检查 ApplicationContext 是否正常
+        System.out.println("ApplicationContext: " + (applicationContext != null ? "正常" : "null"));
+
+        // 检查所有 Bean
+        String[] beanNames = applicationContext.getBeanDefinitionNames();
+        boolean foundMapper = false;
+        for (String beanName : beanNames) {
+            if (beanName.toLowerCase().contains("dppetltaskmapper") ||
+                    beanName.contains("DppEtlTaskMapper")) {
+                System.out.println("找到 Mapper Bean: " + beanName);
+                foundMapper = true;
+            }
+        }
+
+        if (!foundMapper) {
+            System.out.println("未找到 DppEtlTaskMapper Bean");
+            // 检查所有 Mapper 类型的 Bean
+            try {
+                Map<String, Object> mappers = applicationContext.getBeansWithAnnotation(org.apache.ibatis.annotations.Mapper.class);
+                System.out.println("找到的 Mapper Beans: " + mappers.keySet());
+            } catch (Exception e) {
+                System.out.println("获取 Mapper Beans 时出错: " + e.getMessage());
+            }
+        }
+
+        // 检查 Mapper 是否注入
+        if (dppEtlTaskMapper == null) {
+            System.out.println("❌ DppEtlTaskMapper 注入失败");
+            // 尝试手动获取
+            try {
+                TestDppEtlTaskMapper mapper = applicationContext.getBean(TestDppEtlTaskMapper.class);
+                System.out.println("✅ 通过 ApplicationContext 获取 Mapper 成功");
+                dppEtlTaskMapper = mapper;
+            } catch (Exception e) {
+                System.out.println("❌ 通过 ApplicationContext 获取 Mapper 也失败: " + e.getMessage());
+                return; // 如果获取不到,直接返回
+            }
+        } else {
+            System.out.println("✅ DppEtlTaskMapper 注入成功");
+        }
+
+        // 如果 Mapper 存在,继续测试
+        if (dppEtlTaskMapper != null) {
+            testSelectJoinPage();
+        }
     }
 
+    private void testSelectJoinPage() {
+        System.out.println("=== 开始测试 selectJoinPage 方法 ===");
+
+        MPJLambdaWrapper<DppEtlTaskDO> wrapper = new MPJLambdaWrapper<>();
+        wrapper.eq(DppEtlTaskDO::getDelFlag, "0");
+
+        try {
+            IPage<DppEtlTaskDO> result = dppEtlTaskMapper.selectJoinPage(
+                    new Page<>(1, 5),
+                    DppEtlTaskDO.class,
+                    wrapper
+            );
+            System.out.println("✅ MyBatis-Plus Join 工作正常!");
+            System.out.println("查询到 " + result.getRecords().size() + " 条记录");
+        } catch (Exception e) {
+            System.out.println("❌ MyBatis-Plus Join 配置有问题: " + e.getMessage());
+            e.printStackTrace();
+        }
+    }
 }

+ 100 - 0
ruoyi-admin/src/test/java/com/ruoyi/MyBatisJoinTest.java

@@ -0,0 +1,100 @@
+package com.ruoyi;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import com.ruoyi.model.dpp.dal.dataobject.etl.DppEtlTaskDO;
+import com.ruoyi.model.etl.mapper.DppEtlTaskMapper;
+import org.junit.jupiter.api.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.ApplicationContext;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.Map;
+
+import static org.junit.Assert.assertNotNull;
+
+@SpringBootTest(classes = RuoYiApplication.class)
+@RunWith(SpringRunner.class)
+public class MyBatisJoinTest {
+
+    @Autowired(required = false)  // 设置为非必需,避免启动失败
+    private DppEtlTaskMapper dppEtlTaskMapper;
+
+    @Autowired
+    private ApplicationContext applicationContext;
+
+    @Test
+    public void testMyBatisPlusJoinConfiguration() {
+        System.out.println("=== 开始诊断 Mapper 注入问题 ===");
+
+        // 检查 ApplicationContext 是否正常
+        System.out.println("ApplicationContext: " + (applicationContext != null ? "正常" : "null"));
+
+        // 检查所有 Bean
+        String[] beanNames = applicationContext.getBeanDefinitionNames();
+        boolean foundMapper = false;
+        for (String beanName : beanNames) {
+            if (beanName.toLowerCase().contains("dppetltaskmapper") ||
+                    beanName.contains("DppEtlTaskMapper")) {
+                System.out.println("找到 Mapper Bean: " + beanName);
+                foundMapper = true;
+            }
+        }
+
+        if (!foundMapper) {
+            System.out.println("未找到 DppEtlTaskMapper Bean");
+            // 检查所有 Mapper 类型的 Bean
+            try {
+                Map<String, Object> mappers = applicationContext.getBeansWithAnnotation(org.apache.ibatis.annotations.Mapper.class);
+                System.out.println("找到的 Mapper Beans: " + mappers.keySet());
+            } catch (Exception e) {
+                System.out.println("获取 Mapper Beans 时出错: " + e.getMessage());
+            }
+        }
+
+        // 检查 Mapper 是否注入
+        if (dppEtlTaskMapper == null) {
+            System.out.println("❌ DppEtlTaskMapper 注入失败");
+            // 尝试手动获取
+            try {
+                DppEtlTaskMapper mapper = applicationContext.getBean(DppEtlTaskMapper.class);
+                System.out.println("✅ 通过 ApplicationContext 获取 Mapper 成功");
+                dppEtlTaskMapper = mapper;
+            } catch (Exception e) {
+                System.out.println("❌ 通过 ApplicationContext 获取 Mapper 也失败: " + e.getMessage());
+                return; // 如果获取不到,直接返回
+            }
+        } else {
+            System.out.println("✅ DppEtlTaskMapper 注入成功");
+        }
+
+        // 如果 Mapper 存在,继续测试
+        if (dppEtlTaskMapper != null) {
+            testSelectJoinPage();
+        }
+    }
+
+    private void testSelectJoinPage() {
+        System.out.println("=== 开始测试 selectJoinPage 方法 ===");
+
+        MPJLambdaWrapper<DppEtlTaskDO> wrapper = new MPJLambdaWrapper<>();
+        wrapper.eq(DppEtlTaskDO::getDelFlag, "0");
+
+        try {
+            IPage<DppEtlTaskDO> result = dppEtlTaskMapper.selectJoinPage(
+                    new Page<>(1, 5),
+                    DppEtlTaskDO.class,
+                    wrapper
+            );
+            System.out.println("✅ MyBatis-Plus Join 工作正常!");
+            System.out.println("查询到 " + result.getRecords().size() + " 条记录");
+        } catch (Exception e) {
+            System.out.println("❌ MyBatis-Plus Join 配置有问题: " + e.getMessage());
+            e.printStackTrace();
+        }
+    }
+}

+ 33 - 0
ruoyi-admin/src/test/java/com/ruoyi/TinyflowTest.java

@@ -10,10 +10,18 @@ import com.agentsflex.core.chain.event.NodeStartEvent;
 import com.agentsflex.core.chain.listener.ChainEventListener;
 import com.agentsflex.core.chain.listener.ChainOutputListener;
 import com.agentsflex.llm.openai.OpenAILlm;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.yulichang.wrapper.MPJLambdaWrapper;
 import com.ruoyi.interfaces.tinyflow.parser.PrintNodeParser;
 import com.ruoyi.interfaces.tinyflow.parser.ServiceNodeParser;
+import com.ruoyi.model.dpp.dal.dataobject.etl.DppEtlTaskDO;
+import com.ruoyi.model.etl.mapper.DppEtlTaskMapper;
 import dev.tinyflow.core.Tinyflow;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
 
+import javax.annotation.Resource;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -232,5 +240,30 @@ public class TinyflowTest {
         System.out.println("result:" + result);*/
 //        TestService testService = new TestService();
 //        System.out.println(testService.helloTest());
+
+
+    }
+
+    @Resource
+    private  DppEtlTaskMapper  dppEtlTaskMapper ;
+
+    @Test
+    public void testSelectJoinPage() {
+
+        MPJLambdaWrapper<DppEtlTaskDO> wrapper = new MPJLambdaWrapper<>();
+        // 添加简单的查询条件
+        wrapper.eq(DppEtlTaskDO::getDelFlag, "0");
+
+        try {
+            IPage<DppEtlTaskDO> result = dppEtlTaskMapper.selectJoinPage(
+                    new Page<>(1, 10),
+                    DppEtlTaskDO.class,
+                    wrapper
+            );
+            System.out.println("查询成功,结果数量:" + result.getRecords().size());
+        } catch (Exception e) {
+            System.out.println("查询失败:" + e.getMessage());
+            e.printStackTrace();
+        }
     }
 }

+ 0 - 1
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/controller/MdEstimateController.java

@@ -9,7 +9,6 @@ import com.ruoyi.interfaces.domain.MdModelInfo;
 import com.ruoyi.interfaces.domain.vo.MdEstimateMdVo;
 import com.ruoyi.interfaces.service.IMdEstimateService;
 import com.ruoyi.interfaces.service.IMdModelInfoService;
-import org.checkerframework.checker.units.qual.A;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 

+ 0 - 1
ruoyi-api-patform/src/main/java/com/ruoyi/interfaces/service/impl/PtServiceLogStatisServiceImpl.java

@@ -7,7 +7,6 @@ import com.ruoyi.interfaces.domain.PtServiceLogStatis;
 import com.ruoyi.interfaces.domain.vo.PtServiceLogStatisVo;
 import com.ruoyi.interfaces.mapper.PtServiceLogStatisMapper;
 import com.ruoyi.interfaces.service.IPtServiceLogStatisService;
-import org.checkerframework.checker.units.qual.A;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 

+ 43 - 0
ruoyi-common/pom.xml

@@ -211,6 +211,48 @@
             <version>3.5.3</version>
         </dependency>
 
+
+        <!-- 格尔KMS SDK -->
+        <dependency>
+            <groupId>org.apache.thrift</groupId>
+            <artifactId>libthrift</artifactId>
+            <version>0.16.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk15on</artifactId>
+            <version>1.62</version>
+        </dependency>
+        <dependency>
+            <groupId>org.yaml</groupId>
+            <artifactId>snakeyaml</artifactId>
+            <version>1.19</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-pool2</artifactId>
+            <version>2.11.1</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.8.16</version>
+        </dependency>
+        <dependency>
+            <groupId>org.javassist</groupId>
+            <artifactId>javassist</artifactId>
+            <version>3.18.0-GA</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>20.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.koal</groupId>
+            <artifactId>kms-sdk</artifactId>
+            <version>1.4.1</version>
+        </dependency>
         <!--
                 <dependency>
                     <groupId>com.agentsflex</groupId>
@@ -219,6 +261,7 @@
                 </dependency>
         -->
 
+
         <dependency>
             <groupId>dev.tinyflow</groupId>
             <artifactId>tinyflow-java-core</artifactId>

+ 8 - 0
ruoyi-common/src/main/java/com/ruoyi/common/enums/DigestAlgorithm.java

@@ -0,0 +1,8 @@
+package com.ruoyi.common.enums;
+
+/**
+ * 摘要算法枚举
+ */
+public enum DigestAlgorithm {
+    SM3
+}

+ 10 - 0
ruoyi-common/src/main/java/com/ruoyi/common/enums/Mode.java

@@ -0,0 +1,10 @@
+package com.ruoyi.common.enums;
+
+/**
+ * 加密模式枚举
+ */
+public enum Mode {
+    CBC,
+    CFB
+}
+

+ 24 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/kms/EncryptResult.java

@@ -0,0 +1,24 @@
+package com.ruoyi.common.utils.kms;
+
+/**
+ * 加密结果封装类
+ */
+class EncryptResult {
+    private String encryptedData;
+    private byte[] encryptedDataBytes;
+    private String iv;
+    private byte[] ivBytes;
+    
+    // getter and setter methods
+    public String getEncryptedData() { return encryptedData; }
+    public void setEncryptedData(String encryptedData) { this.encryptedData = encryptedData; }
+    
+    public byte[] getEncryptedDataBytes() { return encryptedDataBytes; }
+    public void setEncryptedDataBytes(byte[] encryptedDataBytes) { this.encryptedDataBytes = encryptedDataBytes; }
+    
+    public String getIv() { return iv; }
+    public void setIv(String iv) { this.iv = iv; }
+    
+    public byte[] getIvBytes() { return ivBytes; }
+    public void setIvBytes(byte[] ivBytes) { this.ivBytes = ivBytes; }
+}

+ 255 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/kms/KmsWrapper.java

@@ -0,0 +1,255 @@
+package com.ruoyi.common.utils.kms;
+
+import com.ghca.kms.thrift.api.DigestAlgorithm;
+import com.koal.kms.sdk.ed.KmsSdkException;
+import com.koal.kms.sdk.ed.KmsUtil;
+import com.koal.kms.sdk.ed.Mode;
+import org.springframework.stereotype.Component;
+import javax.annotation.PostConstruct;
+import java.util.Base64;
+
+/**
+ * KMS工具类封装
+ *
+ */
+@Component
+public class KmsWrapper {
+    
+    private static final Base64.Encoder BASE64_ENCODER = Base64.getEncoder();
+    private static final Base64.Decoder BASE64_DECODER = Base64.getDecoder();
+    
+/*    *//**
+     * 初始化KMS客户端
+     * 在实际项目中,这里应该读取配置文件进行初始化
+     *//*
+    @PostConstruct
+    public void init() {
+        // 这里应该根据实际SDK进行初始化
+        // 例如:KmsUtil.init(config);
+    }*/
+
+    // ==================== 数据加密相关方法 ====================
+    
+    /**
+     * CBC模式加密文本(推荐使用)
+     */
+    public String encryptTextCBC(String plainText) throws KmsSdkException {
+        byte[] encryptedData = KmsUtil.encrypt(
+            plainText.getBytes(java.nio.charset.StandardCharsets.UTF_8), 
+            Mode.CBC,
+            null
+        );
+        return BASE64_ENCODER.encodeToString(encryptedData);
+    }
+    
+    /**
+     * CFB模式加密文本
+     */
+    public EncryptResult encryptTextCFB(String plainText) throws KmsSdkException {
+        // 生成随机IV
+        byte[] iv = KmsUtil.generateRandom(16);
+        byte[] encryptedData = KmsUtil.encrypt(
+            plainText.getBytes(java.nio.charset.StandardCharsets.UTF_8), 
+            Mode.CFB, 
+            iv
+        );
+        
+        EncryptResult result = new EncryptResult();
+        result.setEncryptedData(BASE64_ENCODER.encodeToString(encryptedData));
+        result.setIv(BASE64_ENCODER.encodeToString(iv));
+        return result;
+    }
+    
+    /**
+     * CBC模式加密字节数据
+     */
+    public byte[] encryptDataCBC(byte[] plainData) throws KmsSdkException {
+        return KmsUtil.encrypt(plainData, Mode.CBC, null);
+    }
+    
+    /**
+     * CFB模式加密字节数据
+     */
+    public EncryptResult encryptDataCFB(byte[] plainData) throws KmsSdkException {
+        byte[] iv = KmsUtil.generateRandom(16);
+        byte[] encryptedData = KmsUtil.encrypt(plainData, Mode.CFB, iv);
+        
+        EncryptResult result = new EncryptResult();
+        result.setEncryptedDataBytes(encryptedData);
+        result.setIvBytes(iv);
+        return result;
+    }
+    
+    // ==================== 数据解密相关方法 ====================
+    
+    /**
+     * CBC模式解密文本
+     */
+    public String decryptTextCBC(String encryptedText) throws KmsSdkException {
+        byte[] encryptedData = BASE64_DECODER.decode(encryptedText);
+        byte[] decryptedData = KmsUtil.decrypt(encryptedData, Mode.CBC, null);
+        return new String(decryptedData, java.nio.charset.StandardCharsets.UTF_8);
+    }
+    
+    /**
+     * CFB模式解密文本
+     */
+    public String decryptTextCFB(String encryptedText, String ivBase64) throws KmsSdkException {
+        byte[] encryptedData = BASE64_DECODER.decode(encryptedText);
+        byte[] iv = BASE64_DECODER.decode(ivBase64);
+        byte[] decryptedData = KmsUtil.decrypt(encryptedData, Mode.CFB, iv);
+        return new String(decryptedData, java.nio.charset.StandardCharsets.UTF_8);
+    }
+    
+    /**
+     * CBC模式解密字节数据
+     */
+    public byte[] decryptDataCBC(byte[] encryptedData) throws KmsSdkException {
+        return KmsUtil.decrypt(encryptedData, Mode.CBC, null);
+    }
+    
+    /**
+     * CFB模式解密字节数据
+     */
+    public byte[] decryptDataCFB(byte[] encryptedData, byte[] iv) throws KmsSdkException {
+        return KmsUtil.decrypt(encryptedData, Mode.CFB, iv);
+    }
+    
+    // ==================== 服务端加密解密 ====================
+    
+    /**
+     * 服务端加密(使用主密钥)
+     */
+    public String encryptServerSide(String plainText) throws KmsSdkException {
+        byte[] encryptedData = KmsUtil.encrypt(
+            plainText.getBytes(java.nio.charset.StandardCharsets.UTF_8)
+        );
+        return BASE64_ENCODER.encodeToString(encryptedData);
+    }
+    
+    /**
+     * 服务端解密(使用主密钥)
+     */
+    public String decryptServerSide(String encryptedText) throws KmsSdkException {
+        byte[] encryptedData = BASE64_DECODER.decode(encryptedText);
+        byte[] decryptedData = KmsUtil.decrypt(encryptedData);
+        return new String(decryptedData, java.nio.charset.StandardCharsets.UTF_8);
+    }
+    
+    /**
+     * 服务端加密字节数据
+     */
+    public byte[] encryptServerSide(byte[] plainData) throws KmsSdkException {
+        return KmsUtil.encrypt(plainData);
+    }
+    
+    /**
+     * 服务端解密字节数据
+     */
+    public byte[] decryptServerSide(byte[] encryptedData) throws KmsSdkException {
+        return KmsUtil.decrypt(encryptedData);
+    }
+    
+    // ==================== 随机数生成 ====================
+    
+    /**
+     * 生成随机字符串(Base64编码)
+     */
+    public String generateRandomBase64(int length) throws KmsSdkException {
+        byte[] randomBytes = KmsUtil.generateRandom(length);
+        return BASE64_ENCODER.encodeToString(randomBytes);
+    }
+    
+    /**
+     * 生成随机字节数组
+     */
+    public byte[] generateRandomBytes(int length) throws KmsSdkException {
+        return KmsUtil.generateRandom(length);
+    }
+    
+    /**
+     * 生成16字节IV(用于CFB模式)
+     */
+    public String generateIVBase64() throws KmsSdkException {
+        return generateRandomBase64(16);
+    }
+    
+    /**
+     * 生成16字节IV字节数组
+     */
+    public byte[] generateIVBytes() throws KmsSdkException {
+        return generateRandomBytes(16);
+    }
+    
+    // ==================== 文件操作 ====================
+    
+    /**
+     * 文件加密
+     */
+    public void encryptFile(String sourceFilePath, String targetFileName) throws KmsSdkException {
+        KmsUtil.encryptFile(sourceFilePath, targetFileName);
+    }
+    
+    /**
+     * 文件解密
+     */
+    public void decryptFile(String sourceFilePath, String targetFileName) throws KmsSdkException {
+        KmsUtil.decryptFile(sourceFilePath, targetFileName);
+    }
+    
+    // ==================== HMAC运算 ====================
+    
+    /**
+     * HMAC运算(SM3)
+     */
+    public String hmacBase64(String data) throws KmsSdkException {
+        byte[] hmacData = KmsUtil.hMac(
+            data.getBytes(java.nio.charset.StandardCharsets.UTF_8), 
+            DigestAlgorithm.SM3
+        );
+        return BASE64_ENCODER.encodeToString(hmacData);
+    }
+    
+    /**
+     * HMAC运算字节数据
+     */
+    public byte[] hmac(byte[] data) throws KmsSdkException {
+        return KmsUtil.hMac(data, DigestAlgorithm.SM3);
+    }
+    
+    /**
+     * 验证HMAC
+     */
+    public boolean verifyHmac(String data, String hmacBase64) throws KmsSdkException {
+        byte[] dataBytes = data.getBytes(java.nio.charset.StandardCharsets.UTF_8);
+        byte[] hmacBytes = BASE64_DECODER.decode(hmacBase64);
+        return KmsUtil.verifyHMac(dataBytes, hmacBytes, DigestAlgorithm.SM3);
+    }
+    
+    /**
+     * 验证HMAC字节数据
+     */
+    public boolean verifyHmac(byte[] data, byte[] hmacData) throws KmsSdkException {
+        return KmsUtil.verifyHMac(data, hmacData, DigestAlgorithm.SM3);
+    }
+    
+    // ==================== 摘要运算 ====================
+    
+    /**
+     * 计算摘要(SM3)
+     */
+    public String hashBase64(String data) throws KmsSdkException {
+        byte[] hashData = KmsUtil.hash(
+            data.getBytes(java.nio.charset.StandardCharsets.UTF_8), 
+            DigestAlgorithm.SM3
+        );
+        return BASE64_ENCODER.encodeToString(hashData);
+    }
+    
+    /**
+     * 计算摘要字节数据
+     */
+    public byte[] hash(byte[] data) throws KmsSdkException {
+        return KmsUtil.hash(data, DigestAlgorithm.SM3);
+    }
+}

+ 70 - 5
ruoyi-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java → ruoyi-framework/src/main/java/com/ruoyi/framework/config/MybatisPlusConfig.java

@@ -2,13 +2,18 @@ package com.ruoyi.framework.config;
 
 import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
 import com.baomidou.mybatisplus.extension.incrementer.H2KeyGenerator;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
 import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
+import com.github.yulichang.interceptor.MPJInterceptor;
 import com.ruoyi.common.utils.StringUtils;
 import org.apache.ibatis.io.VFS;
 import org.mybatis.spring.annotation.MapperScan;
 import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.core.env.Environment;
 import org.springframework.core.io.DefaultResourceLoader;
@@ -18,6 +23,7 @@ import org.springframework.core.io.support.ResourcePatternResolver;
 import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
 import org.springframework.core.type.classreading.MetadataReader;
 import org.springframework.core.type.classreading.MetadataReaderFactory;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
 import org.springframework.util.ClassUtils;
 
 import javax.sql.DataSource;
@@ -28,19 +34,67 @@ import java.util.HashSet;
 import java.util.List;
 
 /**
- * Mybatis支持*匹配扫描包
+ * Mybatis Plus 配置
  *
- * @author ruoyi
+ * @author qdata
  */
+@EnableTransactionManagement(proxyTargetClass = true)
 @Configuration
 @MapperScan("com.ruoyi.**.mapper")
-public class MyBatisConfig {
+@ComponentScan(basePackages = "com.ruoyi")
+public class MybatisPlusConfig
+{
+    @Bean
+    public MybatisPlusInterceptor mybatisPlusInterceptor()
+    {
+
+
+        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+        // 分页插件
+        interceptor.addInnerInterceptor(paginationInnerInterceptor());
+        // 乐观锁插件
+        interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor());
+        // 阻断插件
+        interceptor.addInnerInterceptor(blockAttackInnerInterceptor());
+        return interceptor;
+    }
+
+    /**
+     * 分页插件,自动识别数据库类型 https://baomidou.com/guide/interceptor-pagination.html
+     */
+    public PaginationInnerInterceptor paginationInnerInterceptor()
+    {
+        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
+        // 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbType
+        // paginationInnerInterceptor.setDbType(DbType.MYSQL);
+        // 设置最大单页限制数量,默认 500 条,-1 不受限制
+        paginationInnerInterceptor.setMaxLimit(-1L);
+        return paginationInnerInterceptor;
+    }
+
+    /**
+     * 乐观锁插件 https://baomidou.com/guide/interceptor-optimistic-locker.html
+     */
+    public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor()
+    {
+        return new OptimisticLockerInnerInterceptor();
+    }
+
+    /**
+     * 如果是对全表的删除或更新操作,就会终止该操作 https://baomidou.com/guide/interceptor-block-attack.html
+     */
+    public BlockAttackInnerInterceptor blockAttackInnerInterceptor()
+    {
+        return new BlockAttackInnerInterceptor();
+    }
+
+
 
     static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
 
     private final Environment env;
 
-    public MyBatisConfig(Environment env) {
+    public MybatisPlusConfig(Environment env) {
         this.env = env;
     }
 
@@ -112,6 +166,15 @@ public class MyBatisConfig {
         sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
         sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));
         sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
+
+        // 手动设置插件,确保 MPJInterceptor 在拦截器链中
+        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+        interceptor.addInnerInterceptor(paginationInnerInterceptor());
+        interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor());
+        interceptor.addInnerInterceptor(blockAttackInnerInterceptor());
+
+        sessionFactory.setPlugins(interceptor);
+
         return sessionFactory;
     }
 
@@ -120,4 +183,6 @@ public class MyBatisConfig {
         return new H2KeyGenerator();
     }
 
+
+
 }

+ 23 - 33
ruoyi-model-dpp/src/main/java/com/ruoyi/model/etl/mapper/DppEtlTaskMapper.java

@@ -10,12 +10,11 @@ import com.ruoyi.model.dpp.controller.etl.vo.DppEtlTaskPageReqVO;
 import com.ruoyi.model.dpp.controller.etl.vo.DppEtlTaskRespVO;
 import com.ruoyi.model.dpp.dal.dataobject.etl.DppEtlTaskDO;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * 数据集成任务Mapper接口
@@ -23,44 +22,35 @@ import java.util.Set;
  * @author qdata
  * @date 2025-02-13
  */
+
 public interface DppEtlTaskMapper extends BaseMapperX<DppEtlTaskDO> {
 
     IPage<DppEtlTaskRespVO> getDppEtlTaskPage(Page page, @Param("params") DppEtlTaskPageReqVO reqVO);
 
-    default PageResult<DppEtlTaskDO> selectPage(DppEtlTaskPageReqVO reqVO) {
-        // 定义排序的字段(防止 SQL 注入,与数据库字段名称一致)
-        Set<String> allowedColumns = new HashSet<>(Arrays.asList("id", "create_time", "update_time"));
-
-        MPJLambdaWrapper<DppEtlTaskDO> lambdaWrapper = new MPJLambdaWrapper();
 
-        String leftJoin = TaskCatEnum.findEnumByType(reqVO.getType()) + " t2 on t.CAT_CODE = t2.CODE AND t2.DEL_FLAG = '0'";
 
-        lambdaWrapper.selectAll(DppEtlTaskDO.class)
-                .select("t2.NAME AS catName",
-                        "t3.CRON_EXPRESSION AS cronExpression"
-                        , "t3.STATUS AS schedulerState"
-                        , "(SELECT MAX(ti.CREATE_TIME) FROM DPP_ETL_TASK_INSTANCE ti WHERE ti.TASK_CODE = t.CODE AND ti.DEL_FLAG = '0') AS lastExecuteTime")
-                .leftJoin(leftJoin)
-                .leftJoin("DPP_ETL_SCHEDULER t3 ON t.id = t3.task_id AND t3.DEL_FLAG = '0'")
-                .eq(StringUtils.isNotBlank(reqVO.getType()), DppEtlTaskDO::getType, reqVO.getType())
-                .likeRight(StringUtils.isNotBlank(reqVO.getCatCode()), DppEtlTaskDO::getCatCode, reqVO.getCatCode())
-                .like(StringUtils.isNotBlank(reqVO.getName()), DppEtlTaskDO::getName, reqVO.getName())
-                .eq(StringUtils.isNotBlank(reqVO.getCode()), DppEtlTaskDO::getCode, reqVO.getCode())
-                .ne(DppEtlTaskDO::getStatus, "-2")
-                .ne(DppEtlTaskDO::getStatus, "-3")
-                .eq(reqVO.getProjectId() != null, DppEtlTaskDO::getProjectId, reqVO.getProjectId())
-                .eq(StringUtils.isNotBlank(reqVO.getProjectCode()), DppEtlTaskDO::getProjectCode, reqVO.getProjectCode())
-                .eq(StringUtils.isNotBlank(reqVO.getPersonCharge()), DppEtlTaskDO::getPersonCharge, reqVO.getPersonCharge())
-                .eq(StringUtils.isNotBlank(reqVO.getLocations()), DppEtlTaskDO::getLocations, reqVO.getLocations())
-                .eq(StringUtils.isNotBlank(reqVO.getDescription()), DppEtlTaskDO::getDescription, reqVO.getDescription())
-                .eq(StringUtils.isNotBlank(reqVO.getStatus()), DppEtlTaskDO::getStatus, reqVO.getStatus())
-                .orderByStr(StringUtils.isNotBlank(reqVO.getOrderByColumn()), StringUtils.equals("asc", reqVO.getIsAsc()), StringUtils.isNotBlank(reqVO.getOrderByColumn()) ? Arrays.asList(reqVO.getOrderByColumn().split(",")) : null);
-
-        // 构造动态查询条件
-        return selectJoinPage(reqVO, DppEtlTaskDO.class, lambdaWrapper);
+    default PageResult<DppEtlTaskDO> selectPage(DppEtlTaskPageReqVO reqVO) {
+        // 直接在 reqVO 中设置动态表名(如果需要)
+        if (StringUtils.isNotBlank(reqVO.getType())) {
+            // 如果 XML 中无法直接调用静态方法,可以在 Java 中设置
+            // 这里假设你已经在 reqVO 中添加了 dynamicTableName 字段
+            String tableName = TaskCatEnum.findEnumByType(reqVO.getType()).toString();
+            // 通过反射或其他方式设置到 reqVO 中,或者在 XML 中处理
+        }
+
+        // 调用 XML 中定义的方法
+        IPage<DppEtlTaskDO> pageResult = selectJoinPage(
+                new Page<>(reqVO.getPageNum(), reqVO.getPageSize()),
+                reqVO
+        );
+
+        // 直接返回,不需要转换
+        return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
     }
 
 
+    IPage<DppEtlTaskDO> selectJoinPage(Page<DppEtlTaskDO> page, @Param("reqVO") DppEtlTaskPageReqVO reqVO);
+
     int checkTaskIdInSubTasks(Long id);
 
     int checkTaskIdInDatasource(@Param("datasourceIdList") List<Long> datasourceIdList, @Param("projectIdList") List<Long> projectIdList);

+ 7 - 0
ruoyi-model-dpp/src/main/java/com/ruoyi/model/etl/mapper/TestDppEtlTaskMapper.java

@@ -0,0 +1,7 @@
+package com.ruoyi.model.etl.mapper;
+
+import com.github.yulichang.base.MPJBaseMapper;
+import com.ruoyi.model.dpp.dal.dataobject.etl.DppEtlTaskDO;
+
+public interface  TestDppEtlTaskMapper  extends MPJBaseMapper<DppEtlTaskDO> {
+}

+ 100 - 0
ruoyi-model-dpp/src/main/resources/mapper/etl/DppEtlTaskMapper.xml

@@ -397,4 +397,104 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             </choose>
         </if>
     </select>
+
+    <resultMap id="DppEtlTaskDOResultMap" type="com.ruoyi.model.dpp.dal.dataobject.etl.DppEtlTaskDO">
+        <!-- 主表字段映射 -->
+        <id column="id" property="id"/>
+        <result column="code" property="code"/>
+        <result column="name" property="name"/>
+        <result column="type" property="type"/>
+        <result column="cat_code" property="catCode"/>
+        <result column="status" property="status"/>
+        <result column="project_id" property="projectId"/>
+        <result column="project_code" property="projectCode"/>
+        <result column="person_charge" property="personCharge"/>
+        <result column="locations" property="locations"/>
+        <result column="description" property="description"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_time" property="updateTime"/>
+
+        <!-- 关联表字段映射 -->
+        <result column="catName" property="catName"/>
+        <result column="cronExpression" property="cronExpression"/>
+        <result column="schedulerState" property="schedulerState"/>
+        <result column="lastExecuteTime" property="lastExecuteTime"/>
+    </resultMap>
+
+    <select id="selectJoinPage" resultMap="DppEtlTaskDOResultMap">
+        SELECT
+        t.*,
+        t2.NAME AS catName,
+        t3.CRON_EXPRESSION AS cronExpression,
+        t3.STATUS AS schedulerState,
+        (SELECT MAX(ti.CREATE_TIME) FROM DPP_ETL_TASK_INSTANCE ti WHERE ti.TASK_CODE = t.CODE AND ti.DEL_FLAG = '0') AS lastExecuteTime
+        FROM DPP_ETL_TASK t
+        <!-- 动态表名连接 -->
+        <choose>
+            <when test="reqVO.type != null and reqVO.type != ''">
+                LEFT JOIN ${@com.ruoyi.common.enums.TaskCatEnum@findEnumByType(reqVO.type)} t2
+                ON t.CAT_CODE = t2.CODE AND t2.DEL_FLAG = '0'
+            </when>
+            <otherwise>
+                LEFT JOIN DPP_TASK_CAT t2 ON t.CAT_CODE = t2.CODE AND t2.DEL_FLAG = '0'
+            </otherwise>
+        </choose>
+        LEFT JOIN DPP_ETL_SCHEDULER t3 ON t.id = t3.task_id AND t3.DEL_FLAG = '0'
+        WHERE t.DEL_FLAG = '0'
+
+        <!-- 查询条件 -->
+        <if test="reqVO.type != null and reqVO.type != ''">
+            AND t.TYPE = #{reqVO.type}
+        </if>
+        <if test="reqVO.catCode != null and reqVO.catCode != ''">
+            AND t.CAT_CODE LIKE CONCAT(#{reqVO.catCode}, '%')
+        </if>
+        <if test="reqVO.name != null and reqVO.name != ''">
+            AND t.NAME LIKE CONCAT('%', #{reqVO.name}, '%')
+        </if>
+        <if test="reqVO.code != null and reqVO.code != ''">
+            AND t.CODE = #{reqVO.code}
+        </if>
+        AND t.STATUS NOT IN ('-2', '-3')
+        <if test="reqVO.projectId != null">
+            AND t.PROJECT_ID = #{reqVO.projectId}
+        </if>
+        <if test="reqVO.projectCode != null and reqVO.projectCode != ''">
+            AND t.PROJECT_CODE = #{reqVO.projectCode}
+        </if>
+        <if test="reqVO.personCharge != null and reqVO.personCharge != ''">
+            AND t.PERSON_CHARGE = #{reqVO.personCharge}
+        </if>
+        <if test="reqVO.locations != null and reqVO.locations != ''">
+            AND t.LOCATIONS = #{reqVO.locations}
+        </if>
+        <if test="reqVO.description != null and reqVO.description != ''">
+            AND t.DESCRIPTION = #{reqVO.description}
+        </if>
+        <if test="reqVO.status != null and reqVO.status != ''">
+            AND t.STATUS = #{reqVO.status}
+        </if>
+
+        <!-- 排序处理 -->
+        <choose>
+            <when test="reqVO.orderByColumn != null and reqVO.orderByColumn != ''">
+                ORDER BY
+                <foreach item="column" index="index" collection="reqVO.orderByColumn.split(',')" separator=",">
+                    <choose>
+                        <when test="column == 'id' or column == 'create_time' or column == 'update_time'">
+                            t.${column}
+                        </when>
+                        <otherwise>t.id</otherwise>
+                    </choose>
+                </foreach>
+                <choose>
+                    <when test="reqVO.isAsc != null and reqVO.isAsc == 'asc'">ASC</when>
+                    <otherwise>DESC</otherwise>
+                </choose>
+            </when>
+            <otherwise>
+                ORDER BY t.id DESC
+            </otherwise>
+        </choose>
+    </select>
 </mapper>