andy 1 年之前
父節點
當前提交
0baf41c339
共有 69 個文件被更改,包括 6151 次插入3170 次删除
  1. 1 1
      .gitignore
  2. 2 3
      Dockerfile
  3. 8 0
      DockerfileGraalvm
  4. 19 0
      build-docker-image.sh
  5. 二進制
      config/config.sqlite
  6. 23 5
      pom.xml
  7. 63 4
      request2.http
  8. 56 0
      request3.http
  9. 210 126
      src/main/java/com/scbfkj/uni/api/ControlApi.java
  10. 15 6
      src/main/java/com/scbfkj/uni/api/FileApi.java
  11. 60 40
      src/main/java/com/scbfkj/uni/api/GenericApi.java
  12. 45 28
      src/main/java/com/scbfkj/uni/api/LogAop.java
  13. 47 45
      src/main/java/com/scbfkj/uni/api/SecurityApi.java
  14. 1 22
      src/main/java/com/scbfkj/uni/api/WebSocketServer.java
  15. 13 0
      src/main/java/com/scbfkj/uni/exceptions/ConnectionNotFoundException.java
  16. 9 0
      src/main/java/com/scbfkj/uni/exceptions/ContainerNotFoundException.java
  17. 7 0
      src/main/java/com/scbfkj/uni/exceptions/ServiceNotFoundException.java
  18. 7 0
      src/main/java/com/scbfkj/uni/exceptions/ServiceTypeException.java
  19. 22 0
      src/main/java/com/scbfkj/uni/exceptions/SqlBatchQueryException.java
  20. 37 8
      src/main/java/com/scbfkj/uni/library/DataAliasGetUtil.java
  21. 362 163
      src/main/java/com/scbfkj/uni/library/DataEncryptionUtil.java
  22. 262 50
      src/main/java/com/scbfkj/uni/library/DataFormatUtil.java
  23. 21 3
      src/main/java/com/scbfkj/uni/library/EmailUtil.java
  24. 36 9
      src/main/java/com/scbfkj/uni/library/FileUtil.java
  25. 21 3
      src/main/java/com/scbfkj/uni/library/IbmmqUtil.java
  26. 98 47
      src/main/java/com/scbfkj/uni/library/ImageUtil.java
  27. 226 79
      src/main/java/com/scbfkj/uni/library/MapTools.java
  28. 220 91
      src/main/java/com/scbfkj/uni/library/RequestUtil.java
  29. 49 20
      src/main/java/com/scbfkj/uni/library/RsaUtils.java
  30. 67 1
      src/main/java/com/scbfkj/uni/library/UniReturnUtil.java
  31. 30 94
      src/main/java/com/scbfkj/uni/library/UserUtil.java
  32. 270 139
      src/main/java/com/scbfkj/uni/library/XmlUtil.java
  33. 44 2
      src/main/java/com/scbfkj/uni/library/script/AuthorizationScriptUtil.java
  34. 446 253
      src/main/java/com/scbfkj/uni/library/script/DatabaseScriptUtil.java
  35. 41 5
      src/main/java/com/scbfkj/uni/library/script/HttpScriptUtil.java
  36. 125 58
      src/main/java/com/scbfkj/uni/library/script/JavaScriptEngineUtil.java
  37. 17 22
      src/main/java/com/scbfkj/uni/library/script/JsScriptEngineUtil.java
  38. 38 3
      src/main/java/com/scbfkj/uni/library/script/KafkaScriptUtil.java
  39. 86 33
      src/main/java/com/scbfkj/uni/process/ActiveMQ.java
  40. 515 195
      src/main/java/com/scbfkj/uni/process/DataBase.java
  41. 305 150
      src/main/java/com/scbfkj/uni/process/Elasticsearch.java
  42. 37 55
      src/main/java/com/scbfkj/uni/process/Email.java
  43. 69 49
      src/main/java/com/scbfkj/uni/process/FTP.java
  44. 66 30
      src/main/java/com/scbfkj/uni/process/Http.java
  45. 242 34
      src/main/java/com/scbfkj/uni/process/IBMMQ.java
  46. 195 74
      src/main/java/com/scbfkj/uni/process/JMS.java
  47. 81 20
      src/main/java/com/scbfkj/uni/process/Kafka.java
  48. 101 19
      src/main/java/com/scbfkj/uni/process/RabbitMQ.java
  49. 50 50
      src/main/java/com/scbfkj/uni/process/SocketClient.java
  50. 69 26
      src/main/java/com/scbfkj/uni/process/Web.java
  51. 31 12
      src/main/java/com/scbfkj/uni/process/ZeroMQ.java
  52. 125 39
      src/main/java/com/scbfkj/uni/service/ControlService.java
  53. 0 454
      src/main/java/com/scbfkj/uni/service/DataProcessService.java
  54. 251 150
      src/main/java/com/scbfkj/uni/service/LoggerService.java
  55. 448 258
      src/main/java/com/scbfkj/uni/service/SecurityService.java
  56. 75 6
      src/main/java/com/scbfkj/uni/system/Config.java
  57. 179 56
      src/main/java/com/scbfkj/uni/system/ProcessUtil.java
  58. 24 3
      src/main/java/com/scbfkj/uni/system/ScheduleTask.java
  59. 66 50
      src/main/java/com/scbfkj/uni/system/ScheduleUtil.java
  60. 16 7
      src/main/java/com/scbfkj/uni/system/SystemInit.java
  61. 34 13
      src/main/java/com/scbfkj/uni/utils/Util.java
  62. 15 0
      src/main/resources/application-catest.yml
  63. 15 0
      src/main/resources/application-center.yml
  64. 3 0
      src/main/resources/application-hw.yml
  65. 8 20
      src/test/java/com/scbfkj/uni/library/JsonPathTest.java
  66. 25 31
      src/test/java/com/scbfkj/uni/process/DataBaseTest.java
  67. 1 1
      src/test/java/com/scbfkj/uni/process/IBMMQTest.java
  68. 0 4
      src/test/java/com/scbfkj/uni/process/KafkaTest.java
  69. 1 1
      src/test/java/com/scbfkj/uni/process/RabbitMQTest.java

+ 1 - 1
.gitignore

@@ -33,4 +33,4 @@ build/
 .vscode/
 /images/
 /jdk/
-./*Test.java
+/src/test/

+ 2 - 3
Dockerfile

@@ -1,7 +1,6 @@
 # 选择运行时基础镜像
-FROM tencent-kona-jdk:17.0.9
-RUN mkdir "/app"
+FROM kona-jdk:17_0_10_b1
 WORKDIR /app
 COPY target/*.jar /app/app.jar
 EXPOSE 9500
-ENTRYPOINT ["java","-jar","app.jar"]
+ENTRYPOINT ["/app/TencentKona-17.0.10.b1/bin/java","-jar","/app/app.jar"]

+ 8 - 0
DockerfileGraalvm

@@ -0,0 +1,8 @@
+# 选择运行时基础镜像
+FROM graalvm-ce:jdk17-js
+#RUN mkdir "/app"
+WORKDIR /app
+RUN gu install js
+COPY target/*.jar /app/app.jar
+EXPOSE 9500
+ENTRYPOINT ["java","-jar","app.jar"]

+ 19 - 0
build-docker-image.sh

@@ -0,0 +1,19 @@
+now=$(date +%Y%m%d)
+if [ $# -eq 0 ]; then
+    echo "镜像名称"
+    exit 1
+fi
+tag=$0
+if [ $# -eq 1 ]; then
+    echo "请输入版本号"
+    exit 1
+fi
+version=$1
+
+if [ $# -eq 2 ]; then
+    echo "请输入版本号"
+    filePath=$2
+else
+    filePath=Dockerfile
+fi
+docker build -t $tag:$version-$now -f $filePath .

二進制
config/config.sqlite


+ 23 - 5
pom.xml

@@ -5,12 +5,12 @@
     <parent>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
-        <version>3.2.1</version>
+        <version>3.2.5</version>
         <relativePath/> <!-- lookup parent from repository -->
     </parent>
     <groupId>com.scbfkj</groupId>
     <artifactId>uni</artifactId>
-    <version>0.0.1</version>
+    <version>2.0.5</version>
     <name>uni</name>
     <description>uni</description>
     <properties>
@@ -18,6 +18,7 @@
         <maven.compiler.source>17</maven.compiler.source>
         <maven.compiler.target>17</maven.compiler.target>
         <graalvm.version>23.0.1</graalvm.version>
+        <maven.build.timestamp.format>yyyyMMdd</maven.build.timestamp.format>
     </properties>
     <dependencies>
         <dependency>
@@ -50,9 +51,12 @@
         <dependency>
             <groupId>org.apache.activemq</groupId>
             <artifactId>artemis-jakarta-client</artifactId>
-            <version>2.32.0</version>
         </dependency>
-
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-compress</artifactId>
+            <version>1.26.0</version>
+        </dependency>
 
         <dependency>
             <groupId>com.rabbitmq.jms</groupId>
@@ -164,9 +168,23 @@
         </dependency>
 
     </dependencies>
+    <profiles>
+        <profile>
+            <id>default</id>
+            <build>
+                <finalName>${project.artifactId}-${project.version}</finalName>
+            </build>
+        </profile>
 
+        <profile>
+            <id>tag</id>
+            <build>
+                <finalName>${project.artifactId}-${project.version}-${maven.build.timestamp}</finalName>
+                <!-- Additional plugin configurations or dependencies -->
+            </build>
+        </profile>
+    </profiles>
     <build>
-        <!--<finalName>${project.artifactId}-${project.version}-${maven.build.timestamp}</finalName>-->
         <plugins>
             <plugin>
                 <groupId>org.springframework.boot</groupId>

+ 63 - 4
request2.http

@@ -1,6 +1,6 @@
 
-@host=http://localhost:9500
-#@host=http://120.26.64.82:9500
+#@host=http://localhost:9500
+@host=http://120.26.64.82:9500
 ###
 
 POST {{host}}/user/getToken
@@ -15,7 +15,7 @@ Content-Type: application/json
 ###
 POST {{host}}/user/verifyCode
 Content-Type: application/json
-sessionid: a0c8503c3386a506c20247e2e26fa4d6
+sessionid: 3d12d7f18898f8fcea6059946189c375
 
 {}
 
@@ -24,7 +24,7 @@ sessionid: a0c8503c3386a506c20247e2e26fa4d6
 ###
 POST {{host}}/user/login
 Content-Type: application/json
-sessionid: a0c8503c3386a506c20247e2e26fa4d6
+sessionid: 3d12d7f18898f8fcea6059946189c375
 
 {
   "account": "zhaowei",
@@ -77,4 +77,63 @@ Content-Type: application/json
 {
   "serviceid": "139",
   "containercode": "test"
+}
+
+###
+POST http://120.26.64.82:9500/openApi/query
+usertoken: 58dae03c8a0553dc1e50f32d8dbc4358
+sessionid: 43616ffaf8209ca2dae16e7c272cd602
+Content-Type: application/json;charset=UTF-8
+
+{
+  "serviceid": 15,
+  "datacontent": {
+    "filter": {
+      "serviceid": 5
+    }
+  },
+  "event": "0",
+  "page": 1,
+  "size": 9999
+}
+
+
+###
+POST http://120.26.64.82:9500/openApi/query
+Content-Type: application/json
+usertoken: abefa0f41006104d9b2ee8aba9f3f296
+sessionid: 9dd97c42fd2f13ed27ec1e4359c14609
+
+
+{
+  "page": 1,
+  "serviceid": 151,
+  "datacontent": {
+    "username": "dev",
+    "email": "l7871878100@hotmail.com"
+  },
+  "event": "0"
+}
+###
+POST http://localhost:18888/openApi/sendemail
+Content-Type: application/json
+
+{
+  "datacontent": {
+    "context": "测试邮件 勿回!",
+    "subject": "测试邮件",
+    "email": "liyuxuan@airchina.com "
+  }
+}
+
+
+
+###
+WEBSOCKET ws://localhost:9500/ws
+Content-Type: application/json
+
+
+{
+  "message": "Hello, server!",
+  "repeat": 3
 }

+ 56 - 0
request3.http

@@ -0,0 +1,56 @@
+
+@exampleServer=localhost:9500
+###
+### Simple WebSocket Request
+// It is possible to send messages to server right from the Services tool window
+WEBSOCKET ws://{{exampleServer}}/ws
+
+### Request with client messages
+// It is possible to specify client messages in request body. Use '===' to separate messages.
+// Add '=== wait-for-server' above a message to send it after a server response is received.
+// To wait for N responses, add '=== wait-for-server' N times.
+WEBSOCKET ws://{{exampleServer}}/app/service
+Content-Type: application/json // We use it for highlighting
+
+
+{
+  "message": "Hello, server!",
+  "repeat": 3
+}
+
+### Requests with scripts
+// Also, we can use scripts for sending messages to server and verifying messages from the server.
+WEBSOCKET ws://{{exampleServer}}/app/service
+Content-Type: application/json
+
+{
+  "message": "Beginning message"
+}
+
+> {%
+    var i = 0
+    response.body.onEachMessage((message, unsubscribe, output) => {
+        i++
+        debugger
+        const jsonMessage = JSON.parse(message); // We know that our sample server returns JSON
+        client.test("Server sent a JSON with 'message' property: " + i, () => {
+            client.assert(jsonMessage.message !== undefined)
+        });
+        if (jsonMessage.message.includes("finish")) {
+            unsubscribe() // remove current listener
+            return
+        }
+
+        if (i === 5) {
+            output(JSON.stringify({
+                message: "finish"
+            }));
+        } else {
+            output(JSON.stringify({
+                message: "Message from the script: " + i
+            }));
+        }
+    }, () => {
+        client.log("We stopped listening for WebSocket from the current 'onEachMessage' call!")
+    });
+%}

+ 210 - 126
src/main/java/com/scbfkj/uni/api/ControlApi.java

@@ -1,5 +1,6 @@
 package com.scbfkj.uni.api;
 
+import com.scbfkj.uni.exceptions.ContainerNotFoundException;
 import com.scbfkj.uni.library.DataAliasGetUtil;
 import com.scbfkj.uni.library.RequestUtil;
 import com.scbfkj.uni.library.UniReturnUtil;
@@ -18,133 +19,216 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 
+/**
+ * ControlApi类用于提供控制功能的API接口。
+ */
 @RestController
 @RequestMapping("controlApi")
 public class ControlApi {
-    private static final DataBase DATA_BASE = new DataBase();
-    private final static String SERVICE_ID = "serviceid";
-
-    @Value("${app.inner.ssl.enable:false}")
-    private boolean httpSslEnable = false;
-
-    @PostMapping("start")
-    public ResponseEntity<Map<String, Object>> start(@RequestBody Map<String, Object> body) throws Exception {
-        Optional<String> serviceIdOpt = DataAliasGetUtil.getValue(SERVICE_ID, body);
-        Optional<String> containerCode = DataAliasGetUtil.getValue("containercode", body);
-        if ((serviceIdOpt.isEmpty() || containerCode.isEmpty())) {
-            return ResponseEntity.ok(UniReturnUtil.fail("服务ID不能为空"));
-        }
-
-        String code = containerCode.get();
-        if (!Config.getContainerCode().equals(code)) {
-            List<Map<String, Object>> containers = DATA_BASE.query(Config.getCenterConnectionStr(), "select * from container where containercode = ? limit 1 offset 0", code);
-            if (containers.isEmpty()) {
-                return ResponseEntity.ok(UniReturnUtil.fail("容器编号错误"));
-            } else {
-                Map<String, Object> containerMap = containers.get(0);
-                Object requesturi = containerMap.get("requesturi");
-                if (requesturi == null) {
-                    return ResponseEntity.ok(UniReturnUtil.fail("不知道容器的访问地址"));
-                }
-                String url = requesturi.toString();
-                if (!url.startsWith("http")) {
-                    if (httpSslEnable) {
-                        url = "https://" + url + "/controlApi/start";
-                    } else {
-                        url = "http://" + url + "/controlApi/start";
-                    }
-                }
-                Map<String, Object> stringObjectMap = new Web().execWebApi(RequestUtil.getHeaders(), "post", body, url);
-                return ResponseEntity.ok(stringObjectMap);
-            }
-        }
-
-        Map<String, Object> started = ControlService.startOrStop(body, "1", false);
-        return ResponseEntity.ok(started);
-    }
-
-    /**
-     * 主动采集与被动采集的停止
-     *
-     * @param body 请求内容
-     * @return
-     */
-    @PostMapping("stop")
-    public ResponseEntity<Map<String, Object>> stop(@RequestBody Map<String, Object> body) throws Exception {
-        Optional<String> serviceIdOpt = DataAliasGetUtil.getValue(SERVICE_ID, body);
-        Optional<String> containerCode = DataAliasGetUtil.getValue("containercode", body);
-        if ((serviceIdOpt.isEmpty() || containerCode.isEmpty())) {
-            return ResponseEntity.ok(UniReturnUtil.fail("服务ID不能为空"));
-        }
-
-        String code = containerCode.get();
-        if (!Config.getContainerCode().equals(code)) {
-            List<Map<String, Object>> containers = DATA_BASE.query(Config.getCenterConnectionStr(), "select * from container where containercode = ? limit 1 offset 0", code);
-            if (containers.isEmpty()) {
-                return ResponseEntity.ok(UniReturnUtil.fail("容器编号错误"));
-            } else {
-                Map<String, Object> containerMap = containers.get(0);
-                Object requesturi = containerMap.get("requesturi");
-                if (requesturi == null) {
-                    return ResponseEntity.ok(UniReturnUtil.fail("不知道容器的访问地址"));
-                }
-                String url = requesturi.toString();
-                if (!url.startsWith("http")) {
-                    if (httpSslEnable) {
-                        url = "https://" + url + "/controlApi/stop";
-                    } else {
-                        url = "http://" + url + "/controlApi/stop";
-                    }
-                }
-                Map<String, Object> stringObjectMap = new Web().execWebApi(RequestUtil.getHeaders(), "post", body, url);
-                return ResponseEntity.ok(stringObjectMap);
-            }
-        }
-
-
-
-        Map<String, Object> stoped = ControlService.startOrStop(body, "0", false);
-
-        return ResponseEntity.ok(stoped);
-    }
-
-    @PostMapping("startAll")
-    public ResponseEntity<Map<String, Object>> startAll(@RequestBody Map<String, Object> body) throws Exception {
-        Map<String, Object> started = ControlService.startOrStop(body, "1", true);
-        return ResponseEntity.ok(started);
-    }
-
-    /**
-     * 主动采集与被动采集的停止
-     *
-     * @param body 请求内容
-     * @return
-     */
-    @PostMapping("stopAll")
-    public ResponseEntity<Map<String, Object>> stopAll(@RequestBody Map<String, Object> body) throws Exception {
-        Map<String, Object> stoped = ControlService.startOrStop(body, "0", true);
-        return ResponseEntity.ok(stoped);
-    }
-
-
-    /**
-     * 清理缓存
-     *
-     * @param body 请求内容
-     * @return
-     */
-    @PostMapping("cleanCache")
-    public ResponseEntity<Map<String, Object>> cleanCache(@RequestBody Map<String, Object> body) throws Exception {
-        Optional<String> table = DataAliasGetUtil.getValue("table", body);
-        table.ifPresent(tableName -> {
-            List<String> keys = DataBase.cacheDatas.keySet().stream().filter(it -> it.contains(tableName)).toList();
-            keys.parallelStream().forEach(DataBase.cacheDatas::remove);
-        });
-        if (table.isEmpty()) {
-            DataBase.cacheDatas.clear();
-        }
-        return ResponseEntity.ok(UniReturnUtil.success(true));
-    }
-
-
+	// 数据库实例
+	private static final DataBase DATA_BASE = new DataBase();
+
+	// 服务ID常量
+	private static final String SERVICE_ID = "serviceid";
+
+	// 是否启用HTTPS的配置
+	@Value("${app.inner.ssl.enable:false}")
+	private boolean httpSslEnable = false;
+
+	/**
+	 * 启动某个服务实例。
+	 *
+	 * @param body 包含启动服务所需信息的Map对象,其中应至少包含服务ID和容器代码。
+	 *
+	 * @return 返回一个ResponseEntity对象,其中包含启动结果的信息。如果启动成功,返回成功的Map;如果启动失败,返回包含错误信息的Map。
+	 *
+	 * @throws Exception 如果启动过程中遇到异常,则抛出。
+	 */
+	@PostMapping("start")
+	public ResponseEntity<Map<String, Object>> start(@RequestBody Map<String, Object> body) throws Exception {
+		// 从请求体中获取服务ID和容器代码
+		Optional<String> serviceIdOpt = DataAliasGetUtil.getValue(SERVICE_ID, body);
+		Optional<String> containerCode = DataAliasGetUtil.getValue("containercode", body);
+
+		// 检查服务ID和容器代码是否为空
+		if ( serviceIdOpt.isEmpty() || containerCode.isEmpty() ) {
+			return ResponseEntity.ok(UniReturnUtil.fail("服务ID不能为空"));
+		}
+
+		String code = containerCode.get();
+		// 检查容器代码是否为预期的代码
+		if ( ! Config.getContainerCode().equals(code) ) {
+			// 如果不是预期的容器代码,则尝试从数据库中查询该容器的信息
+			List<Map<String, Object>> containers = DATA_BASE.query(Config.getCenterConnectionStr(), "select * from container where containercode = ? limit 1 offset 0", code);
+
+			// 如果查询结果为空,表示容器代码错误
+			if ( containers.isEmpty() ) {
+				return ResponseEntity.ok(UniReturnUtil.fail("容器编号错误"));
+			} else {
+				Map<String, Object> containerMap = containers.get(0);
+				Object requesturi = containerMap.get("requesturi");
+				// 检查容器的访问地址是否为空
+				if ( requesturi == null ) {
+					return ResponseEntity.ok(UniReturnUtil.fail("不知道容器的访问地址"));
+				}
+				String url = requesturi.toString();
+				// 根据是否启用HTTPS,构造完整的API调用URL
+				if ( ! url.startsWith("http") ) {
+					if ( httpSslEnable ) {
+						url = "https://" + url + "/controlApi/start";
+					} else {
+						url = "http://" + url + "/controlApi/start";
+					}
+				}
+				// 向指定的URL发送启动请求
+				Map<String, Object> stringObjectMap = new Web().execWebApi(RequestUtil.getHeaders(), "post", body, url);
+				return ResponseEntity.ok(stringObjectMap);
+			}
+		}
+
+		// 如果是预期的容器代码,则直接调用ControlService的启动方法
+		Map<String, Object> started = null;
+		try {
+			started = ControlService.startOrStop(body, "1", false);
+		} catch ( ContainerNotFoundException e ) {
+			started = UniReturnUtil.fail(e);
+		}
+		return ResponseEntity.ok(started);
+	}
+
+	/**
+	 * 停止主动采集与被动采集的任务。 该接口会根据请求内容中的服务ID和容器编码,判断是否为本机操作,若非本机则远程调用相应容器的停止接口。
+	 *
+	 * @param body 请求内容,应包含服务ID和容器编码等必要信息。
+	 *
+	 * @return 返回操作结果,成功则为成功信息,失败则为失败原因。
+	 *
+	 * @throws Exception 如果操作过程中出现异常,则抛出。
+	 */
+	@PostMapping("stop")
+	public ResponseEntity<Map<String, Object>> stop(@RequestBody Map<String, Object> body) throws Exception {
+		// 从请求体中获取服务ID和容器编码
+		Optional<String> serviceIdOpt = DataAliasGetUtil.getValue(SERVICE_ID, body);
+		Optional<String> containerCode = DataAliasGetUtil.getValue("containercode", body);
+
+		// 检查服务ID和容器编码是否为空
+		if ( (serviceIdOpt.isEmpty() || containerCode.isEmpty()) ) {
+			return ResponseEntity.ok(UniReturnUtil.fail("服务ID不能为空"));
+		}
+
+		// 验证容器编码是否为本地配置的编码,若不一致则尝试远程停止采集
+		String code = containerCode.get();
+		if ( ! Config.getContainerCode().equals(code) ) {
+			// 查询数据库,验证容器编码是否存在
+			List<Map<String, Object>> containers = DATA_BASE.query(Config.getCenterConnectionStr(), "select * from container where containercode = ? limit 1 offset 0", code);
+			if ( containers.isEmpty() ) {
+				return ResponseEntity.ok(UniReturnUtil.fail("容器编号错误"));
+			} else {
+				// 获取容器的访问地址,并构造停止采集的API请求URL
+				Map<String, Object> containerMap = containers.get(0);
+				Object requesturi = containerMap.get("requesturi");
+				if ( requesturi == null ) {
+					return ResponseEntity.ok(UniReturnUtil.fail("不知道容器的访问地址"));
+				}
+				String url = requesturi.toString();
+				if ( ! url.startsWith("http") ) {
+					if ( httpSslEnable ) {
+						url = "https://" + url + "/controlApi/stop";
+					} else {
+						url = "http://" + url + "/controlApi/stop";
+					}
+				}
+				// 发起停止采集的API请求
+				Map<String, Object> stringObjectMap = new Web().execWebApi(RequestUtil.getHeaders(), "post", body, url);
+				return ResponseEntity.ok(stringObjectMap);
+			}
+		}
+
+		// 本地停止采集操作
+		Map<String, Object> stoped = null;
+		try {
+			stoped = ControlService.startOrStop(body, "0", false);
+		} catch ( ContainerNotFoundException e ) {
+			stoped = UniReturnUtil.fail(e);
+		}
+		return ResponseEntity.ok(stoped);
+	}
+
+	/**
+	 * 启动所有相关容器。
+	 *
+	 * @param body 包含启动所需信息的Map对象,具体信息由服务端解析确定。
+	 *
+	 * @return 返回一个ResponseEntity对象,其中包含启动结果的信息。如果启动成功,返回包含启动信息的Map;如果启动失败,返回错误信息。
+	 *
+	 * @throws Exception 如果在启动过程中发生异常,则抛出Exception。
+	 */
+	@PostMapping("startAll")
+	public ResponseEntity<Map<String, Object>> startAll(@RequestBody Map<String, Object> body) throws Exception {
+		Map<String, Object> started = null;
+		try {
+			// 尝试启动所有容器
+			started = ControlService.startOrStop(body, "1", true);
+		} catch ( ContainerNotFoundException e ) {
+			// 如果找不到容器,返回失败信息
+			started = UniReturnUtil.fail(e);
+		}
+		return ResponseEntity.ok(started);
+	}
+
+	/**
+	 * 停止主动采集与被动采集的操作。
+	 * <p>
+	 * 该接口通过接收请求内容来停止所有的采集任务。它会尝试停止主动采集和被动采集。 如果相关容器未被找到,则会返回相应的错误信息。
+	 *
+	 * @param body 请求内容,通常包含特定的参数来标识需要停止的采集任务,具体参数依赖于业务逻辑。
+	 *
+	 * @return 返回一个包含操作结果的状态码和信息的Map。成功时,返回操作结果;失败时,返回错误信息。
+	 *
+	 * @throws Exception 如果停止过程中发生异常,则会抛出异常。
+	 */
+	@PostMapping("stopAll")
+	public ResponseEntity<Map<String, Object>> stopAll(@RequestBody Map<String, Object> body) throws Exception {
+		Map<String, Object> stoped = null;
+		try {
+			// 尝试停止采集任务
+			stoped = ControlService.startOrStop(body, "0", true);
+		} catch ( ContainerNotFoundException e ) {
+			// 如果找不到容器,返回失败信息
+			stoped = UniReturnUtil.fail(e);
+		}
+		// 返回操作结果
+		return ResponseEntity.ok(stoped);
+	}
+
+	/**
+	 * 清理缓存。 该方法根据请求内容中的"table"字段来决定清理特定表的缓存数据,如果请求中没有指定表名,则清理所有缓存。
+	 *
+	 * @param body 请求内容,预期为一个Map,其中可能包含键名为"table"的项来指定需要清理的表名。
+	 *
+	 * @return 返回一个响应实体,包含操作成功与否的信息。
+	 *
+	 * @throws Exception 如果处理过程中发生异常,则抛出。
+	 */
+	@PostMapping("cleanCache")
+	public ResponseEntity<Map<String, Object>> cleanCache(@RequestBody Map<String, Object> body) throws Exception {
+		// 尝试从请求体中获取"table"字段指定的表名
+		Optional<String> table = DataAliasGetUtil.getValue("table", body);
+		// 如果存在指定表名,清理该表相关的缓存数据
+		table.ifPresent(tableName -> {
+			// 筛选出与指定表名相关的缓存键
+			List<String> keys = DataBase.getCacheData().keySet().stream().filter(it -> it.contains(tableName)).toList();
+			// 并行流方式移除这些键对应的缓存数据
+			keys.parallelStream().forEach(DataBase.getCacheData()::remove);
+			DataBase.getColumns().remove(tableName);
+		});
+		// 如果没有指定表名,清理所有缓存数据
+		if ( table.isEmpty() ) {
+			DataBase.getCacheData().clear();
+			DataBase.getColumns().clear();
+		}
+		DataBase.getCacheConfigList().clear();
+		// 返回操作成功的响应
+		return ResponseEntity.ok(UniReturnUtil.success(true));
+	}
 }

+ 15 - 6
src/main/java/com/scbfkj/uni/api/FileApi.java

@@ -17,19 +17,28 @@ import java.util.Set;
 @RestController
 @RequestMapping("/file")
 public class FileApi {
-
+    // 定义接受的文件类型集合
     private static final Set<String> CONTENT_TYPES = Set.of("application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
 
+    /**
+     * 上传文件的接口。
+     *
+     * @param file 用户上传的文件,通过multipart/form-data类型提交。
+     * @return 返回一个响应实体,包含上传结果的信息。
+     * @throws IOException 如果读取文件时发生错误。
+     */
     @PostMapping("/upload")
     public ResponseEntity<Map<String, Object>> uploadFiles(@RequestParam("file") MultipartFile file) throws IOException {
-        // 处理多个文件上传逻辑
+        // 检查上传文件的类型是否被支持
         if (CONTENT_TYPES.contains(file.getContentType())) {
+            // 将Excel文件转换为Map格式
             Map<String, List<List<String>>> excelToMap = FileUtil.readExcelToMap(file.getInputStream());
 
+            // 文件上传成功,返回成功响应
             return ResponseEntity.ok(UniReturnUtil.success("Files uploaded successfully"));
-        }else{
-        return ResponseEntity.ok(UniReturnUtil.fail("Please upload an Excel file"));
-
+        } else {
+            // 文件类型不支持,返回失败响应
+            return ResponseEntity.ok(UniReturnUtil.fail("Please upload an Excel file"));
         }
     }
-}
+}

+ 60 - 40
src/main/java/com/scbfkj/uni/api/GenericApi.java

@@ -15,50 +15,70 @@ import java.util.Map;
 @RequestMapping
 public class GenericApi {
 
-    private static final DataBase DATA_BASE = new DataBase();
+	private static final DataBase DATA_BASE = new DataBase();
 
-    @PostMapping({"/openApi/newdata", "/openApi/modifydata", "/openApi/movedata", "/openApi/query"})
-    public ResponseEntity<Map<String, Object>> base(@RequestBody Map<String, Object> body) {
-        String uri = RequestUtil.getUri();
-        String event = "0";
+	/**
+	 * 根据请求URI处理不同的数据操作。
+	 *
+	 * @param body 请求体,包含需要处理的数据
+	 *
+	 * @return 返回处理结果,包含处理后的数据和状态信息
+	 */
+	@PostMapping({"/openApi/newdata", "/openApi/modifydata", "/openApi/movedata", "/openApi/query"})
+	public ResponseEntity<Map<String, Object>> base(@RequestBody Map<String, Object> body) {
+		String uri = RequestUtil.getUri(); // 获取当前请求的URI
+		String event = "0"; // 默认事件编码
 
-        if (uri.endsWith("newdata")) {
-            event = "1";
-        } else if (uri.endsWith("modifydata")) {
-            event = "2";
-        } else if (uri.endsWith("movedata")) {
-            event = "3";
-        } else if (uri.endsWith("query")) {
-            event = "0";
-        }
-        body.put("event", event);
-        body.put("headers", RequestUtil.getHeaders());
+		// 根据URI后缀确定具体的事件编码
+		if ( uri.endsWith("newdata") ) {
+			event = "1";
+		} else if ( uri.endsWith("modifydata") ) {
+			event = "2";
+		} else if ( uri.endsWith("movedata") ) {
+			event = "3";
+		} else if ( uri.endsWith("query") ) {
+			event = "0";
+		}
+		// 更新请求体中的事件编码和添加请求头信息
+		body.put("event", event);
+		body.put("headers", RequestUtil.getHeaders());
 
-        Map<String, Object> process = new ProcessUtil().process(body);
-        return ResponseEntity.ok(process);
-    }
+		// 处理请求体并返回处理结果
+		Map<String, Object> process = new ProcessUtil().process(body);
+		return ResponseEntity.ok(process);
+	}
 
-    /**
-     * 匹配服务的暴露的接口
-     *
-     * @param body
-     * @return
-     * @throws Exception
-     */
+	/**
+	 * 根据请求URI匹配对应的服务,并执行服务处理。
+	 *
+	 * @param body 请求体,包含需要处理的数据
+	 *
+	 * @return 返回处理结果,包含处理后的数据和状态信息
+	 *
+	 * @throws Exception 如果匹配服务失败则抛出异常
+	 */
+	@PostMapping("/**")
+	public ResponseEntity<Map<String, Object>> matchService(@RequestBody(required = false) @RequestAttribute(required = false) @RequestParam(required = false) Map<String, Object> body) throws Exception {
+		if ( body == null ) {
+			return ResponseEntity.ok(Map.of("code", "400", "msg", "请求体不能为空"));
+		}
+		String uri = RequestUtil.getUri(); // 获取当前请求的URI
 
-    @PostMapping("/**")
-    public ResponseEntity<Map<String, Object>> matchService(@RequestBody Map<String, Object> body) throws Exception {
-        String uri = RequestUtil.getUri();
-        List<Map<String, Object>> serviceinfoList = DATA_BASE.query(Config.getCenterConnectionStr(), """
-                select serviceid
-                from serviceinfo
-                where urilist like concat('%', ?, '%')""", uri);
-        if (serviceinfoList.isEmpty()) {
-            return ResponseEntity.status(HttpStatusCode.valueOf(404)).build();
-        }
-        Object serviceid = serviceinfoList.get(0).get("serviceid");
-        body.put("serviceid", serviceid);
-        return ResponseEntity.ok(new ProcessUtil().process(body));
-    }
+		// 查询数据库,尝试匹配服务
+		List<Map<String, Object>> serviceinfoList = DATA_BASE.query(Config.getCenterConnectionStr(), """
+				select serviceid
+				from serviceinfo
+				where urilist like concat('%', ?, '%')""", uri);
+		if ( serviceinfoList.isEmpty() ) {
+			// 如果没有找到匹配的服务,返回404状态码
+			return ResponseEntity.status(HttpStatusCode.valueOf(404)).build();
+		}
+		// 获取匹配到的服务ID,并更新请求体
+		Object serviceid = serviceinfoList.get(0).get("serviceid");
+		body.put("serviceid", serviceid);
+		// 执行服务处理并返回处理结果
+		return ResponseEntity.ok(new ProcessUtil().process(body));
+	}
 
 }
+

+ 45 - 28
src/main/java/com/scbfkj/uni/api/LogAop.java

@@ -19,31 +19,41 @@ import org.springframework.stereotype.Component;
 import java.time.LocalDateTime;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
-
+/**
+ * 日志切面类,用于拦截指定包下的Api请求,进行日志记录、限流控制、服务状态检查等操作。
+ */
 @Component
 @Aspect
 public class LogAop {
 
+    // 用于存储限流规则的映射
     private static final Map<String, RateLimiter> rateLimiterMap = new HashMap<>();
+    // 数据库操作实例
     private static final DataBase DATA_BASE = new DataBase();
+    // 工具类实例
     @Resource
     private Util util;
 
+    /**
+     * 环绕通知,拦截指定包下的Api请求。
+     *
+     * @param joinPoint 切点表达式匹配到的连接点
+     * @return 返回处理后的响应实体
+     * @throws Throwable 抛出异常时处理
+     */
     @Around(value = "within(com.scbfkj.uni.api.*Api)")
-    public ResponseEntity<Object> invokeAround(ProceedingJoinPoint joinPoint) {
+    public ResponseEntity<Object> invokeAround(ProceedingJoinPoint joinPoint) throws Throwable {
         LocalDateTime requestTime = LocalDateTime.now();
-//        请求
+        // 获取请求信息
         String uri = RequestUtil.getUri();
-
-//        请求参数
         Object[] args = joinPoint.getArgs();
         Map<String, Object> returnData = null;
         String message = null;
         Map<String, Object> userInfo = RequestUtil.getUserInfo();
 
-
-        Optional serviceid = Optional.empty();
+        Optional<String> serviceid = Optional.empty();
         String userId = RequestUtil.getUserId();
+        // Debug模式下的日志打印
         if (Config.isDebug()) {
             System.out.println("请求参数:" + DataFormatUtil.toString(args));
             System.out.println("请求路径:" + uri);
@@ -54,16 +64,14 @@ public class LogAop {
         }
 
         try {
-            Map body = null;
-
-//            判断服务状态是否为健康状态 runstate!=0 只判断openApi接口
-            if (args.length > 0 && (!uri.startsWith("/controlApi")&&!uri.startsWith("/file")&&!uri.startsWith("/user")&&!uri.startsWith("/foxlibc")&&!uri.startsWith("/ws"))) {
+            Map<String, Object> body = null;
+            // 检查除特定接口外的服务状态
+            if (args.length > 0 && !uri.startsWith("/controlApi") && !uri.startsWith("/file") && !uri.startsWith("/user") && !uri.startsWith("/foxlibc") && !uri.startsWith("/ws")) {
                 Object arg = args[0];
-                if (arg instanceof Map map) {
-//                    查找serviceid
-                    body = map;
+                if (arg instanceof Map<?, ?> map) {
+                    body = (Map<String, Object>) map;
                     Util.addFilter(body, serviceid, uri, true);
-                    serviceid = DataAliasGetUtil.getValue("serviceid", map);
+                    serviceid = DataAliasGetUtil.getValue("serviceid", (Map<String, Object>) map);
                     if (serviceid.isEmpty()) {
                         List<Map<String, Object>> query = DATA_BASE.query(Config.getCenterConnectionStr(), "select * from serviceinfo where urilist=?", uri);
                         if (!query.isEmpty()) {
@@ -71,15 +79,14 @@ public class LogAop {
                         }
                     }
                     if (serviceid.isPresent()) {
-//                        查找状态
-                        List<Map<String, Object>> mapList = DATA_BASE.query(Config.getCenterConnectionStr(), """
-                                select runstate from servicestate where stoptime is null and  serviceid=? and containercode = ?""", serviceid.get(), Config.getContainerCode());
+                        // 检查服务运行状态
+                        List<Map<String, Object>> mapList = DATA_BASE.query(Config.getCenterConnectionStr(), "select runstate from servicestate where stoptime is null and  serviceid=? and containercode = ?", serviceid.get(), Config.getContainerCode());
                         if (mapList.isEmpty()) {
                             throw new RuntimeException("服务没有运行或者被熔断");
                         } else {
                             Map<String, Object> serviceState = mapList.get(0);
                             Object o = serviceState.get("runstate");
-//                            判断服务状态
+                            // 判断服务状态
                             if (Objects.equals(o.toString(), "0")) {
                                 throw new RuntimeException("服务没有运行或者被熔断");
                             }
@@ -88,19 +95,20 @@ public class LogAop {
                 }
             }
 
+            // 检查是否符合限流规则
             message = checkratelimitrule(uri);
-
             if (Objects.nonNull(message)) {
                 return ResponseEntity.ok(UniReturnUtil.fail(message));
             }
 
-
+            // 继续执行原方法逻辑
             ResponseEntity<Map<String, Object>> responseEntity = (ResponseEntity<Map<String, Object>>) joinPoint.proceed(args);
             Map<String, Object> responseEntityBody = responseEntity.getBody();
             if (responseEntity.getStatusCode().is2xxSuccessful()) {
                 if (Config.isDebug()) {
                     System.out.println("返回值:" + DataFormatUtil.toString(returnData));
                 }
+                // 处理返回数据,如果是调试模式,直接返回
                 if ("0".equals(responseEntityBody.get("code")) && serviceid.isPresent()) {
                     List<Map<String, Object>> serviceInfoes = DATA_BASE.query(Config.getCenterConnectionStr(), "select * from serviceinfo where serviceid=?", serviceid.get());
                     if (!serviceInfoes.isEmpty()) {
@@ -124,10 +132,11 @@ public class LogAop {
             if (Config.isDebug()) {
                 e.printStackTrace();
             }
-//            错误异常消息
+            // 错误处理,生成错误日志消息
             message = UniReturnUtil.getMessage(e);
             returnData = UniReturnUtil.fail(message);
         } finally {
+            // 记录日志
             HashMap<String, Object> logData = new HashMap<>();
             logData.put("requesttime", requestTime);
             logData.put("requestpath", uri);
@@ -145,19 +154,19 @@ public class LogAop {
             LoggerService.log(LoggerService.LogType.INTERFACE, logData);
         }
 
+        // 处理返回数据,过滤和调整
         if (Config.isDebug()) {
             System.out.println("返回值:" + DataFormatUtil.toString(returnData));
         }
 
-
         Object code = returnData.get("code");
-//        过滤返回数据
+        // 过滤返回数据
         if (!Config.isDebug() && Objects.nonNull(code) && "0".equals(code.toString()) && Objects.nonNull(userInfo) && !"0".equals(userInfo.get("usergroupid").toString())) {
             Object returnData1 = returnData.get("returnData");
             if (returnData1 instanceof List<?> ls) {
                 if (serviceid.isPresent()) {
                     try {
-                        List<String> columns = DATA_BASE.query(Config.getSecurityConnectionStr(), "select pagecode from pageconfiguration where pageconfiguration.pageconfigurationid  in (select userpermissions.pageconfigurationid from userpermissions where  userid =? and  serviceid = ?)", userId, serviceid.get()).stream().map(it -> it.get("pagecode").toString()).toList();
+                        List<String> columns = DATA_BASE.query(Config.getSecurityConnectionStr(), "select pagecode from pageconfiguration where pageconfigurationid  in (select userpermissions.pageconfigurationid from userpermissions where  userid =? and  serviceid = ?)", userId, serviceid.get()).stream().map(it -> it.get("pagecode").toString()).toList();
                         List<Object> list = ls.stream().map(it -> {
                             if (it instanceof Map<?, ?> map) {
                                 HashMap<Object, Object> map1 = new HashMap<>();
@@ -181,9 +190,15 @@ public class LogAop {
         return ResponseEntity.ok(returnData);
     }
 
-
+    /**
+     * 检查请求是否符合限流规则。
+     *
+     * @param uri 请求的URI
+     * @return 如果请求超过限流规则,则返回提示消息;否则返回null。
+     * @throws Exception 抛出异常时处理
+     */
     private String checkratelimitrule(String uri) throws Exception {
-
+        // 从数据库查询限流规则
         List<Map<String, Object>> ratelimitruleList = DATA_BASE.query(Config.getSecurityConnectionStr(), "select * from ratelimitrule ");
         Optional<Map<String, Object>> optional = ratelimitruleList.stream().filter(it -> {
             Object pathMatch = it.get("pathmatch");
@@ -194,18 +209,20 @@ public class LogAop {
             Map<String, Object> map = optional.get();
             String pathMatch = map.get("pathmatch").toString();
             if (!rateLimiterMap.containsKey(pathMatch)) {
+                // 创建新的限流器
                 String duration = map.getOrDefault("duration", 1).toString();
                 String limitValue = map.getOrDefault("limitvalue", 100).toString();
                 rateLimiterMap.put(pathMatch, RateLimiter.create(Double.parseDouble(limitValue), Integer.parseInt(duration), TimeUnit.SECONDS));
             }
             RateLimiter rateLimiter = rateLimiterMap.get(pathMatch);
             String timeOut = map.getOrDefault("timeout", 1).toString();
+            // 尝试获取许可,如果失败则表示请求超过限流阈值
             boolean acquire = rateLimiter.tryAcquire(Integer.parseInt(timeOut), TimeUnit.SECONDS);
             if (!acquire) {
                 return map.getOrDefault("returnmessage", "请求频率过高,请降低请求频率").toString();
             }
         }
         return null;
-
     }
 }
+

+ 47 - 45
src/main/java/com/scbfkj/uni/api/SecurityApi.java

@@ -13,19 +13,18 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 
 import java.util.Map;
-
 @RestController
 public class SecurityApi {
 
     @Resource
     private SecurityService securityService;
 
-
     /**
-     * 获取appToken appToken
+     * 获取appToken。
+     * 请求体中需包含相应的认证信息。
      *
-     * @param body
-     * @return
+     * @param body 包含认证信息的请求体
+     * @return 返回包含appToken的响应体
      */
     @PostMapping("user/getToken")
     public ResponseEntity<Map<String, Object>> getToken(@RequestBody Map<String, Object> body) throws Exception {
@@ -33,30 +32,21 @@ public class SecurityApi {
     }
 
     /**
-     * 刷新appToken
+     * 刷新appToken。
+     * 用于更新即将过期或已过期的appToken。
      *
-     * @return
+     * @return 返回新生成的appToken的响应体
      */
     @PostMapping("user/refreshToken")
     public ResponseEntity<Map<String, Object>> refreshToken() throws Exception {
         return ResponseEntity.ok(securityService.refreshToken());
     }
 
-//    /**
-//     * 校验token 包含appToken 和用户token
-//     *
-//     * @return
-//     */
-//    @PostMapping({"user/testToken", "foxlibc/testToken"})
-//    public ResponseEntity<Map<String, Object>> testToken() throws Exception {
-//        String appToken = RequestUtil.getAppToken();
-//        return ResponseEntity.ok(securityService.verifyToken(appToken));
-//    }
-
     /**
-     * 获取验证码
+     * 获取验证码。
+     * 可用于用户注册、登录等场景中的验证码验证。
      *
-     * @return
+     * @return 返回包含验证码信息的响应体
      */
     @PostMapping({"user/verifyCode", "foxlibc/verification-code"})
     public ResponseEntity<Map<String, Object>> getCode() throws Exception {
@@ -64,9 +54,10 @@ public class SecurityApi {
     }
 
     /**
-     * 强制登录
+     * 强制登录。
+     * 用于强制用户进行登录操作。
      *
-     * @return
+     * @return 返回登录状态的响应体
      */
     @PostMapping({"user/forceLogin", "foxlibc/force_sign"})
     public ResponseEntity<Map<String, Object>> forceLogin() throws Exception {
@@ -74,10 +65,11 @@ public class SecurityApi {
     }
 
     /**
-     * 登录
+     * 用户登录。
+     * 提供用户认证信息进行登录操作。
      *
-     * @param body
-     * @return
+     * @param body 包含用户认证信息的请求体
+     * @return 返回登录结果的响应体
      */
     @PostMapping({"user/login", "foxlibc/sign-in"})
     public ResponseEntity<Map<String, Object>> login(@RequestBody Map<String, Object> body) throws Exception {
@@ -85,21 +77,22 @@ public class SecurityApi {
     }
 
     /**
-     * 获取权限
+     * 获取用户权限。
+     * 用于获取当前登录用户所拥有的权限列表。
      *
-     * @return
+     * @return 返回用户权限列表的响应体
      */
     @PostMapping({"user/permissions", "foxlibc/permissions"})
     public ResponseEntity<Map<String, Object>> getPermissions() throws Exception {
-        return ResponseEntity.ok(securityService.permission());
+        return ResponseEntity.ok(securityService.getPermission());
     }
 
-
     /**
-     * 更改密码
+     * 更改密码。
+     * 用户可以使用该接口来更改自己的密码。
      *
-     * @param body
-     * @return
+     * @param body 包含新旧密码信息的请求体
+     * @return 返回密码更改结果的响应体
      */
     @PostMapping({"user/changePassword", "foxlibc/reset-passwd"})
     public ResponseEntity<Map<String, Object>> changePwd(@RequestBody Map<String, Object> body) throws Exception {
@@ -107,9 +100,10 @@ public class SecurityApi {
     }
 
     /**
-     * 登出注销
+     * 登出注销。
+     * 用于用户主动登出或强制登出操作。
      *
-     * @return
+     * @return 返回登出结果的响应体
      */
     @PostMapping({"user/logOut", "foxlibc/sign-out"})
     public ResponseEntity<Map<String, Object>> logOut() throws Exception {
@@ -117,9 +111,10 @@ public class SecurityApi {
     }
 
     /**
-     * 用户心跳检查   判断用户是否在线
+     * 用户心跳检查。
+     * 用于检测用户是否在线,保持用户会话的有效性。
      *
-     * @return
+     * @return 返回用户在线状态的响应体
      */
     @PostMapping({"user/health", "foxlibc/health"})
     public ResponseEntity<Map<String, Object>> health() throws Exception {
@@ -127,9 +122,10 @@ public class SecurityApi {
     }
 
     /**
-     * 获取公钥字符串
+     * 获取公钥字符串。
+     * 用于加密数据时获取系统的公钥。
      *
-     * @return
+     * @return 返回包含公钥信息的响应体
      */
     @PostMapping("user/publicKey")
     public ResponseEntity<Map<String, Object>> getPubKey() {
@@ -140,22 +136,28 @@ public class SecurityApi {
         return ResponseEntity.ok(UniReturnUtil.success(objectNode));
     }
 
-
     /**
-     * 根据传入的type 和id 分别对用户组和用户做授权
+     * 根据传入的type 和id 分别对用户组和用户做授权。
+     * 支持对用户或用户组进行权限授予操作。
+     *
+     * @param body 包含授权信息的请求体
+     * @return 返回授权结果的响应体
      */
-
     @PostMapping("/user/authorization")
     public ResponseEntity<Map<String, Object>> authorization(@RequestBody Map<String, Object> body) throws Exception {
-        return ResponseEntity.ok(AuthorizationScriptUtil.authorization( body));
+        return ResponseEntity.ok(AuthorizationScriptUtil.authorization(body));
     }
 
     /**
-     * 根据传入的type 和id 分别对用户组和用户做授权
+     * 根据传入的type 和id 获取授权信息。
+     * 可用于查询用户或用户组的授权情况。
+     *
+     * @param body 包含授权信息查询条件的请求体
+     * @return 返回授权信息的响应体
      */
-
     @PostMapping("/user/getAuthorization")
     public ResponseEntity<Map<String, Object>> getAuthorization(@RequestBody Map<String, Object> body) throws Exception {
-        return ResponseEntity.ok(AuthorizationScriptUtil.getAuthorization( body));
+        return ResponseEntity.ok(AuthorizationScriptUtil.getAuthorization(body));
     }
 }
+

+ 1 - 22
src/main/java/com/scbfkj/uni/api/WebSocketServer.java

@@ -1,16 +1,11 @@
 package com.scbfkj.uni.api;
 
-import com.scbfkj.uni.library.DataFormatUtil;
-import com.scbfkj.uni.library.UniReturnUtil;
-import com.scbfkj.uni.system.ProcessUtil;
 import jakarta.websocket.*;
 import jakarta.websocket.server.ServerEndpoint;
 import org.springframework.stereotype.Component;
 
 import java.io.IOException;
-import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Map;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 @ServerEndpoint("/ws")
@@ -78,23 +73,7 @@ public class WebSocketServer {
      */
     @OnMessage
     public void onMessage(String message) throws IOException {
-        System.out.println(message);
-        Map<String, Object> result = new HashMap<>();
-        try {
-            Map<?, ?> body = DataFormatUtil.toMap(message);
-            try {
-
-                result = new ProcessUtil().process((Map<String, Object>) body);
-            } catch (Exception e) {
-                result = UniReturnUtil.fail(e);
-            }
-            result.put("request", body);
-        } catch (Exception e) {
-            result.put("request", message);
-        }
-
-        session.getBasicRemote().sendText(DataFormatUtil.toString(result));
-
+//        todo
     }
 
 }

+ 13 - 0
src/main/java/com/scbfkj/uni/exceptions/ConnectionNotFoundException.java

@@ -0,0 +1,13 @@
+package com.scbfkj.uni.exceptions;
+
+public class ConnectionNotFoundException extends Exception {
+
+    public ConnectionNotFoundException(String message) {
+        super(message);
+    }
+
+    public ConnectionNotFoundException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}

+ 9 - 0
src/main/java/com/scbfkj/uni/exceptions/ContainerNotFoundException.java

@@ -0,0 +1,9 @@
+package com.scbfkj.uni.exceptions;
+
+public class ContainerNotFoundException extends Exception {
+
+    public ContainerNotFoundException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}

+ 7 - 0
src/main/java/com/scbfkj/uni/exceptions/ServiceNotFoundException.java

@@ -0,0 +1,7 @@
+package com.scbfkj.uni.exceptions;
+
+public class ServiceNotFoundException extends Throwable {
+    public ServiceNotFoundException(String message) {
+        super(message);
+    }
+}

+ 7 - 0
src/main/java/com/scbfkj/uni/exceptions/ServiceTypeException.java

@@ -0,0 +1,7 @@
+package com.scbfkj.uni.exceptions;
+
+public class ServiceTypeException extends Throwable {
+    public ServiceTypeException(String message) {
+        super(message);
+    }
+}

+ 22 - 0
src/main/java/com/scbfkj/uni/exceptions/SqlBatchQueryException.java

@@ -0,0 +1,22 @@
+package com.scbfkj.uni.exceptions;
+
+public class SqlBatchQueryException extends RuntimeException{
+    public SqlBatchQueryException() {
+    }
+
+    public SqlBatchQueryException(String message) {
+        super(message);
+    }
+
+    public SqlBatchQueryException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public SqlBatchQueryException(Throwable cause) {
+        super(cause);
+    }
+
+    public SqlBatchQueryException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}

+ 37 - 8
src/main/java/com/scbfkj/uni/library/DataAliasGetUtil.java

@@ -7,20 +7,37 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
-
+/**
+ * 提供数据别名获取和生命周期列创建的工具类。
+ */
 public class DataAliasGetUtil {
 
-
+    // 数据库实例
     private static final DataBase DATA_BASE = new DataBase();
+    // 键别名缓存
     private static List<Map<String, Object>> keyAlias = null;
+    // 序列号,用于生成生命周期列
     private static long sequence = 0L;
+    // 上一次生成ID的时间戳
     private static long lastTimestamp = -1L;
 
+    /**
+     * 根据键从数据映射中获取值。如果键直接存在于数据映射中,直接返回该值;如果不在,尝试从键别名表中查找并返回别名值。
+     *
+     * @param key     要获取值的键。
+     * @param data    包含键值对的数据映射。
+     * @return        返回键对应的值,如果不存在则返回空Optional。
+     * @throws Exception 如果操作失败抛出异常。
+     */
     public static Optional<String> getValue(String key, Map<String, Object> data) throws Exception {
 
+        // 检查数据映射是否为空,为空则返回空Optional
         if (Objects.isNull(data)) return Optional.empty();
+        // 尝试直接从数据映射中获取键对应的值
         Optional<String> result = Optional.ofNullable(data.get(key)).map(Object::toString);
+        // 如果值存在,直接返回
         if (result.isPresent()) return result;
+        // 如果键别名缓存未初始化或为空,从数据库查询键别名信息
         if (Objects.isNull(keyAlias) || keyAlias.isEmpty()) {
 
             keyAlias = DATA_BASE.query(Config.getCenterConnectionStr(), """
@@ -28,27 +45,39 @@ public class DataAliasGetUtil {
                     from keyalias""");
 
         }
+        // 从键别名列表中筛选出与键匹配的别名信息
         List<Map<String, Object>> keynames = keyAlias.stream().filter(it -> Objects.equals(it.get("keyname"), key)).toList();
+        // 如果没有找到匹配的别名,返回空Optional
         if (keynames.isEmpty()) return Optional.empty();
+        // 从匹配的别名中查找并返回别名值
         return keynames.stream().map(it -> it.get("aliasname")).map(data::get).filter(Objects::nonNull).map(Object::toString).findAny();
     }
 
+    /**
+     * 创建一个表示生命周期的列名。列名由时间戳、序列号、容器代码和服务ID组成。
+     *
+     * @param containerCode 容器代码,用于生成列名的一部分。
+     * @param serviceId 服务ID,用于生成列名的一部分。
+     * @return 返回生成的生命周期列名。
+     */
     public synchronized static String createLifeCycleCol(String containerCode, String serviceId) {
         long timestamp = System.currentTimeMillis();
-        //如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
-        if (lastTimestamp == timestamp) { //如果是同一时间生成的,则进行毫秒内序列
+        // 检查系统时钟是否回退,如果回退则抛出异常
+        if (lastTimestamp == timestamp) { // 如果是同一时间生成的,则进行毫秒内序列
             sequence++;
-            if (sequence > 999L) {//毫秒内序列溢出
+            // 检查序列号是否溢出,如果溢出则等待下一个时间戳
+            if (sequence > 999L) {// 毫秒内序列溢出
                 sequence = 0;
-                while (lastTimestamp == System.currentTimeMillis()) {//阻塞到下一个毫秒,获得新的时间戳
+                while (lastTimestamp == System.currentTimeMillis()) {// 阻塞到下一个毫秒,获得新的时间戳
                 }
                 timestamp = System.currentTimeMillis();
             }
         } else {
             sequence = 0L;
         }
-        lastTimestamp = timestamp;//上次生成ID的时间截
-        //移位并通过或运算拼到一起组成64位的ID
+        lastTimestamp = timestamp;// 更新上一次生成ID的时间戳
+        // 将时间戳、序列号、容器代码和服務ID组合成一个字符串
         return String.valueOf(timestamp).concat(String.format("%03d", sequence)).concat(String.format("%6s", containerCode)).concat(String.format("%6s", serviceId)).replaceAll("\\s", "0");
     }
 }
+

+ 362 - 163
src/main/java/com/scbfkj/uni/library/DataEncryptionUtil.java

@@ -15,42 +15,43 @@ import java.security.spec.X509EncodedKeySpec;
 import java.util.Base64;
 import java.util.Objects;
 
+
 public class DataEncryptionUtil {
 
 
     //    加密类型
-    public final static String TYPE = "RSA";
+    public static final  String TYPE = "RSA";
     //    加密算法
-    public final static String ALGORITHM = "RSA/ECB/PKCS1Padding";
+    public static final  String ALGORITHM = "RSA/ECB/PKCS1Padding";
     //    私有密钥
     public static String privateKeyStr = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJ9vK5Gsb5hRft3L/OI2rGw8/tg8pSe2L6bfIN8l03YwprUZwi8+R8hdnkR8SSgj2bk3A994L6TAzV8NbG9j+gyj+VakgCjbOSHGywhdKS6QXv0jQ3i8f4kBy4c3uWU9iAwaSTIh78U/8DVmQYRrKMwyqbhx8+ze+2GxaB2ZufEfAgMBAAECgYAyMdTcuxYzNU0k1SkbqyzjstxlBcrVUtVzywHVX1pQ9oY1tBNfvlLpMRg35Y0+tvLADiMJAxS04QKHb3l5JFe/jE24hNxMj2h9JfxO36bGblyqZ7PlS+5/pvXdVaFYolN+5Rocf63/Iq2RSCb8W3D5uUQqLwO/i1iFQT+UROUA4QJBAOvvOJSB4BIu4VD/6XGqZ5cLU3DMtwzHIyvTTH2REGF33eEHc0z83VYi4xbUDGxvDD1d58bPqkpnvJiByXmYVa8CQQCs/mHfpO8fDy7ZKGzs1u4eBsPowSnJLsGbY2mYiaawnHeeLYOaGEdtxRVk06+seTFLw5oi3FDJG8U8LP6FiGeRAkAjZiQeHBJrh/8kcREsjb23KurdDMoWL7a2N6DNYjuL9DklL0H8diAbcWaTIUOv7UVv26wP506MlV31n9uD0/hfAkBo3gwWtrT97wZHPepJ6ECQkylPf0kFXAKhX7Izdb5GcZNRn+WXFAC42jAN3wUvWIg5lWlqmIOgZeU6hUwFRpsBAkEAsSe8v0cho1YTdmXiGQ7uhUxZ455mrw81AdzmuvDxvWFLx1uHAZna9eylZsfbEa7Y9DcmakLJKGWaTvKvYc55ZQ==";
     public static String publicKeyStr = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCfbyuRrG+YUX7dy/ziNqxsPP7YPKUnti+m3yDfJdN2MKa1GcIvPkfIXZ5EfEkoI9m5NwPfeC+kwM1fDWxvY/oMo/lWpIAo2zkhxssIXSkukF79I0N4vH+JAcuHN7llPYgMGkkyIe/FP/A1ZkGEayjMMqm4cfPs3vthsWgdmbnxHwIDAQAB";
 
     /**
-     * 对给定的字符串进行加密操作
+     * 对给定的字符串进行加密操作。
+     * 支持的加密类型有:BASE64、DES、3DES、AES。
+     * 对于DES、3DES、AES加密类型,需要提供密钥。
      *
-     * @param source 原始字符串
-     * @param type   加密类型(BASE64、DES、3DES、AES、)
-     * @param key    密钥(用于DES、3DES、AES)
-     * @return 加密后的字符串
-     * @throws Exception 加密异常
+     * @param source 原始字符串,待加密的字符串。
+     * @param type   加密类型,支持的类型有BASE64、DES、3DES、AES。
+     * @param key    密钥,用于DES、3DES、AES加密。对于BASE64加密,此参数无效。
+     * @return 加密后的字符串。如果加密类型不被支持,则返回null。
+     * @throws Exception 如果加密过程中出现异常,则抛出此异常。
      */
     public static String encrypt(String source, String type, String key) throws Exception {
+        // 根据加密类型选择相应的加密方法
         switch (type.toUpperCase()) {
             case "BASE64" -> {
                 return encryptBase64(source);
             }
             case "DES" -> {
                 return encryptDES(source, key);
-
             }
             case "3DES" -> {
                 return encrypt3DES(source, key);
-
             }
             case "AES" -> {
                 return encryptAES(source, key);
-
             }
             default -> {
                 return null;
@@ -58,16 +59,18 @@ public class DataEncryptionUtil {
         }
     }
 
+
     /**
-     * 对给定的字符串进行解密操作
+     * 对给定的字符串进行解密操作。此函数支持多种加密算法:BASE64、DES、3DES、AES、RSA。
      *
-     * @param source 加密后的字符串
-     * @param type   解密类型(BASE64、DES、3DES、AES、RSA)
-     * @param key    密钥(用于DES、3DES、AES、RSA加密)
-     * @return 解密后的字符串
-     * @throws Exception 解密异常
+     * @param source 加密后的字符串,需要被解密。
+     * @param type   解密类型,指定使用的解密算法。支持的类型有:BASE64、DES、3DES、AES、RSA。
+     * @param key    密钥,用于DES、3DES、AES、RSA等需要密钥的加密算法解密。具体密钥格式要求取决于所使用的加密算法。
+     * @return 解密后的字符串。如果指定的解密类型不支持,则返回null。
+     * @throws Exception 如果解密过程中出现错误,则抛出异常
      */
     public static String decrypt(String source, String type, String key) throws Exception {
+        // 根据解密类型选择相应的解密方法
         switch (type.toUpperCase()) {
             case "BASE64" -> {
                 return decryptBase64(source);
@@ -82,32 +85,47 @@ public class DataEncryptionUtil {
                 return decryptAES(source, key);
             }
             default -> {
+                // 如果没有匹配到任何支持的解密类型,返回null
                 return null;
             }
         }
     }
 
+
     /**
-     * 使用Base64编码对数据进行加密
+     * 使用Base64编码对数据进行加密。此方法将输入的字符串数据转换为字节数组,
+     * 然后使用Base64编码方式对这个字节数组进行编码,最后返回编码后的字符串。
      *
-     * @param data 待加密的数据
-     * @return 加密后的数据
+     * @param data 待加密的数据,类型为String。这是要进行Base64编码的原始数据。
+     * @return 加密后的数据,类型为String。返回的是对原始数据进行Base64编码后的字符串结果。
      */
     public static String encryptBase64(String data) {
+        // 将字符串转换为字节数组,并使用Base64编码,最后返回编码后的字符串
         return Base64.getEncoder().encodeToString(data.getBytes(StandardCharsets.UTF_8));
     }
 
+
     /**
      * 使用Base64解密数据
      *
-     * @param data 要解密的数据
-     * @return 解密后的字符串
+     * @param data 要解密的数据,以Base64编码的字符串形式提供
+     * @return 解密后的字符串。注意:返回的是解密后的文本字符串,而非二进制数据。
      */
     public static String decryptBase64(String data) {
+        // 使用Java Base64工具类的解码器对提供的Base64编码字符串进行解码
         return new String(Base64.getDecoder().decode(data));
     }
 
 
+
+    /**
+     * 使用指定的算法对输入的数据进行SHA签名。
+     *
+     * @param data 需要进行签名的数据。
+     * @param algorithm 使用的加密算法,必须是SHA系列的算法。
+     * @return 返回签名后的数据的十六进制字符串。
+     * @throws NoSuchAlgorithmException 如果指定的加密算法不存在,则抛出此异常。
+     */
     public static String signatureSHA(String data, String algorithm) throws NoSuchAlgorithmException {
         // 创建MessageDigest对象,指定使用SHA算法
         MessageDigest md = MessageDigest.getInstance(checkSHAAlgorithm(algorithm));
@@ -128,292 +146,473 @@ public class DataEncryptionUtil {
     }
 
 
+    /**
+     * 验证加密数据是否与源数据匹配。
+     * 该方法首先通过检查算法名称来确保算法的有效性,然后使用源数据和指定算法生成加密数据的签名。
+     * 如果生成的签名与提供的加密数据相匹配,则验证成功。
+     *
+     * @param encryptedData 加密数据,需验证的数据。
+     * @param algorithm 加密算法,用于生成签名。
+     * @param sourceData 源数据,用于生成签名。
+     * @return boolean 返回验证结果,true表示验证成功,false表示验证失败。
+     * @throws Exception 如果算法名称无效或在生成签名过程中发生错误,则抛出异常。
+     */
     public static boolean verifySHA(String encryptedData, String algorithm, String sourceData) throws Exception {
+        // 生成源数据的签名,并与提供的加密数据进行比较
         return signatureSHA(sourceData, checkSHAAlgorithm(algorithm)).equals(encryptedData);
     }
 
 
+    /**
+     * 使用MD5算法对输入的数据进行加密,并将加密结果转换为十六进制字符串。
+     *
+     * @param data 需要进行MD5加密的原始数据。
+     * @return 经过MD5加密后,转换为十六进制字符串的结果。
+     * @throws NoSuchAlgorithmException 如果系统不支持MD5算法,抛出此异常。
+     */
     public static String signatureMD5(String data) throws NoSuchAlgorithmException {
-        // 创建MessageDigest对象,指定使用MD5算法
+        // 创建MessageDigest对象,用于执行MD5加密
         MessageDigest md = MessageDigest.getInstance("MD5");
 
-        // 将数据转换为字节数组
+        // 将输入的字符串转换为字节数组,以便进行加密
         byte[] dataBytes = data.getBytes();
 
-        // 执行加密操作
+        // 执行MD5加密操作
         byte[] encryptedBytes = md.digest(dataBytes);
 
-        // 将加密后的字节数组转换为十六进制字符串
+        // 将加密后的字节数组转换为十六进制形式的字符串
         StringBuilder sb = new StringBuilder();
         for (byte b : encryptedBytes) {
             sb.append(String.format("%02x", b));
         }
 
+        // 返回转换后的十六进制字符串
         return sb.toString();
     }
 
+    /**
+     * 验证输入数据的MD5加密串是否与给定的加密串匹配。
+     *
+     * @param data 待验证的原始数据。
+     * @param encryptedData 给定的MD5加密字符串。
+     * @return 返回true如果原始数据经过MD5加密后与给定的加密串匹配,否则返回false。
+     * @throws NoSuchAlgorithmException 如果在计算MD5签名时找不到指定的算法。
+     */
     public static boolean verifyMD5(String data, String encryptedData) throws NoSuchAlgorithmException {
+        // 生成原始数据的MD5签名并与给定的加密串比较
         return signatureMD5(data).equals(encryptedData);
     }
 
+    /**
+     * 使用RSA公钥对数据进行加密。
+     *
+     * @param data 需要加密的数据,不能为空。
+     * @return 加密后的数据字符串。
+     * @throws Exception 如果加密过程中出现错误,则抛出异常。
+     */
     public static String encryptRSAByPublicKey(@Nonnull String data) throws Exception {
 
+        // 调用RsaUtils的encrypt方法,使用公钥对数据进行加密
         return RsaUtils.encrypt(data, publicKeyStr);
     }
 
+    /**
+     * 使用私钥对RSA加密的数据进行解密。
+     *
+     * @param data 需要解密的RSA加密数据,使用Base64编码。
+     * @return 解密后的明文数据。
+     * @throws Exception 如果解密过程中发生任何错误,则抛出异常。
+     */
     public static String decryptRSAByPrivateKey(@Nonnull String data) throws Exception {
+        // 使用RsaUtils工具类的decrypt方法,结合私钥字符串对数据进行解密
         return RsaUtils.decrypt(data, privateKeyStr);
     }
 
     /**
-     * 使用DES算法对数据进行加密
+     * 使用DES算法对数据进行加密。
+     * 此方法接收明文数据和密钥,使用DES算法加密数据,然后将加密后的数据以Base64编码的字符串形式返回。
      *
-     * @param data 要加密的数据
-     * @param key  加密密钥
-     * @return 加密后的数据,以Base64编码的字符串形式返回
-     * @throws Exception 加密过程中可能抛出的异常
+     * @param data 要加密的数据,明文。
+     * @param key 加密和解密使用的密钥
+     * @return 加密后的数据,以Base64编码的字符串形式返回
+     * @throws Exception 如果加密过程中出现错误,将抛出异常。
      */
     public static String encryptDES(String data, String key) throws Exception {
-        // 将加密后的字节数组转换为Base64编码的字符串
+        // 将原始字符串数据转换为字节数组,然后使用DES算法进行加密,最后将加密后的字节数组通过Base64编码为字符串
         return Base64.getEncoder().encodeToString(encryptByType(data.getBytes(), "DES", key, "DES/ECB/PKCS5Padding"));
     }
 
+    /**
+     * 使用DES算法解密数据
+     * @param encryptedData 加密后的数据,采用Base64编码
+     * @param key 解密密钥
+     * @return 解密后的字符串
+     * @throws Exception 加密或解密过程中的异常
+     */
     public static String decryptDES(String encryptedData, String key) throws Exception {
-        // 将解密后的字节数组转换为字符串
+        // 将Base64编码的加密数据解码,并使用DES算法进行解密
         return new String(decryptByType(Base64.getDecoder().decode(encryptedData), "DES", key, "DES/ECB/PKCS5Padding"));
     }
 
+    /**
+     * 使用AES算法加密数据
+     * @param data 待加密的字符串数据
+     * @param key 加密密钥
+     * @return 加密后的数据,采用Base64编码
+     * @throws Exception 加密或解密过程中的异常
+     */
     public static String encryptAES(String data, String key) throws Exception {
+        // 使用AES算法加密字符串数据,并将加密后的字节数组转换为Base64编码的字符串
         return Base64.getEncoder().encodeToString(encryptByType(data.getBytes(), "AES", key, "AES/ECB/PKCS5Padding"));
     }
 
+    /**
+     * 使用AES算法解密数据
+     * @param encryptedData 加密后的数据,采用Base64编码
+     * @param key 解密密钥
+     * @return 解密后的字符串
+     * @throws Exception 加密或解密过程中的异常
+     */
     public static String decryptAES(String encryptedData, String key) throws Exception {
+        // 将Base64编码的加密数据解码,并使用AES算法进行解密
         return new String(decryptByType(Base64.getDecoder().decode(encryptedData), "AES", key, "AES/ECB/PKCS5Padding"));
     }
 
+    /**
+     * 使用3DES算法加密数据
+     * @param data 待加密的字符串数据
+     * @param key 加密密钥
+     * @return 加密后的数据,采用Base64编码
+     * @throws Exception 加密或解密过程中的异常
+     */
     public static String encrypt3DES(String data, String key) throws Exception {
+        // 使用3DES算法加密字符串数据,并将加密后的字节数组转换为Base64编码的字符串
         return Base64.getEncoder().encodeToString(encryptByType(data.getBytes(), "DESede", key, "DESede/ECB/PKCS5Padding"));
     }
 
+    /**
+     * 使用3DES算法解密数据
+     * @param encryptedData 加密后的数据,采用Base64编码
+     * @param key 解密密钥
+     * @return 解密后的字符串
+     * @throws Exception 加密或解密过程中的异常
+     */
     public static String decrypt3DES(String encryptedData, String key) throws Exception {
+        // 将Base64编码的加密数据解码,并使用3DES算法进行解密
         return new String(decryptByType(Base64.getDecoder().decode(encryptedData), "DESede", key, "DESede/ECB/PKCS5Padding"));
     }
-
-
     /**
-     * 公钥加密(用于数据加密)
+     * 公钥加密方法。用于对数据进行加密。
      *
-     * @param data         加密前的字符串
-     * @param publicKeyStr base64编码后的公钥
-     * @return base64编码后的字符串
-     * @throws Exception
+     * @param data         需要加密的字符串。
+     * @param publicKeyStr 经过base64编码的公钥字符串。
+     * @param type         密钥类型,如RSA。
+     * @param algorithm    加密算法,如SHA1withRSA。
+     * @return 返回经过base64编码后的加密字符串。
+     * @throws Exception 如果加密过程中出现错误,则抛出异常。
      */
     public static String encryptByPublicKey(@Nonnull String data, @Nonnull String publicKeyStr, @Nonnull String type, @Nonnull String algorithm) throws Exception {
-        //返回base64编码后的字符串
+        // 加密操作,并将结果进行base64编码
         return Base64.getEncoder().encodeToString(doFinalByKeyStr(0, data.getBytes(), publicKeyStr, type, algorithm, Cipher.ENCRYPT_MODE));
     }
 
     /**
-     * 私钥解密(用于数据解密)
+     * 私钥解密方法。用于对经过公钥加密的数据进行解密。
      *
-     * @param data          解密前的字符串
-     * @param privateKeyStr 私钥
-     * @return 解密后的字符串
-     * @throws Exception
+     * @param data          需要解密的字符串,一般是经过base64编码的加密数据。
+     * @param privateKeyStr 私钥字符串。
+     * @param type          密钥类型,如RSA。
+     * @param algorithm     解密算法,如SHA1withRSA。
+     * @return 返回解密后的字符串。
+     * @throws Exception 如果解密过程中出现错误,则抛出异常。
      */
     public static String decryptByPrivateKey(@Nonnull String data, @Nonnull String privateKeyStr, @Nonnull String type, @Nonnull String algorithm) throws Exception {
+        // 解密操作,将解密结果转换为字符串
         return new String(doFinalByKeyStr(1, Base64.getDecoder().decode(data), privateKeyStr, type, algorithm, Cipher.DECRYPT_MODE));
     }
 
     /**
-     * 私钥加密(用于数据加密)
+     * 私钥加密方法。可用于数据加密。
      *
-     * @param data          加密前的字符串
-     * @param privateKeyStr base64编码后的私钥
-     * @return base64编码后的字符串
-     * @throws Exception
+     * @param data          需要加密的字符串。
+     * @param privateKeyStr 经过base64编码的私钥字符串。
+     * @param type          密钥类型,如RSA。
+     * @param algorithm     加密算法,如SHA1withRSA。
+     * @return 返回经过base64编码后的加密字符串。
+     * @throws Exception 如果加密过程中出现错误,则抛出异常。
      */
     public static String encryptByPrivateKey(@Nonnull String data, @Nonnull String privateKeyStr, @Nonnull String type, @Nonnull String algorithm) throws Exception {
+        // 加密操作,并将结果进行base64编码
         return Base64.getEncoder().encodeToString(doFinalByKeyStr(1, data.getBytes(), privateKeyStr, type, algorithm, Cipher.ENCRYPT_MODE));
     }
 
     /**
-     * 公钥解密(用于数据解密)
+     * 公钥解密方法。用于对经过私钥加密的数据进行解密。
      *
-     * @param data         解密前的字符串
-     * @param publicKeyStr 公钥
-     * @return 解密后的字符串
-     * @throws Exception
+     * @param data         需要解密的字符串,一般是经过base64编码的加密数据。
+     * @param publicKeyStr 公钥字符串。
+     * @param type          密钥类型,如RSA。
+     * @param algorithm     解密算法,如SHA1withRSA。
+     * @return 返回解密后的字符串。
+     * @throws Exception 如果解密过程中出现错误,则抛出异常。
      */
     public static String decryptByPublicKey(@Nonnull String data, @Nonnull String publicKeyStr, @Nonnull String type, @Nonnull String algorithm) throws Exception {
+        // 解密操作,将解密结果转换为字符串
         return new String(doFinalByKeyStr(0, Base64.getDecoder().decode(data), publicKeyStr, type, algorithm, Cipher.DECRYPT_MODE));
     }
 
-
     /**
-     * RSA签名
+     * RSA签名方法。用于对数据进行签名操作。
      *
-     * @param data      待签名数据
-     * @param priKey    私钥
-     * @param type      RSA或DSA
-     * @param algorithm SHA1或256
-     * @return 签名
-     * @throws Exception
+     * @param data      需要签名的数据。
+     * @param priKey    私钥
+     * @param type      密钥类型,如RSA或DSA
+     * @param algorithm 签名算法,如SHA1或SHA256
+     * @return 返回签名结果。
+     * @throws Exception 如果签名过程中出现错误,则抛出异常。
      */
     public static String sign(String data, String priKey, String type, String algorithm) throws Exception {
+        // 执行签名操作
         return sign(data.getBytes(), Base64.getDecoder().decode(priKey), type, algorithm);
     }
 
     /**
-     * RSA校验数字签名
+     * RSA验证签名方法。用于验证数据的签名是否有效。
      *
-     * @param data      待校验数据
-     * @param sign      数字签名
-     * @param pubKey    公钥
-     * @param type      RSA或DSA
-     * @param algorithm SHA1或256
-     * @return boolean 校验成功返回true,失败返回false
+     * @param data      需要验证签名的数据。
+     * @param sign      签名数据。
+     * @param pubKey    公钥。
+     * @param type      密钥类型,如RSA或DSA。
+     * @param algorithm 签名算法,如SHA1或SHA256。
+     * @return 返回一个布尔值,表示签名验证是否成功。
+     * @throws Exception 如果验证过程中出现错误,则抛出异常。
      */
     public static boolean verify(String data, String sign, String pubKey, String type, String algorithm) throws Exception {
+        // 验证签名
         return verify(data.getBytes(), Base64.getDecoder().decode(sign), Base64.getDecoder().decode(pubKey), type, algorithm);
     }
+/**
+ * 根据指定的加密类型、密钥和算法对数据进行加密。
+ *
+ * @param data 待加密的数据。
+ * @param type 加密算法的类型(如AES)。
+ * @param key  加密使用的密钥。
+ * @param algorithm 加密算法的名称(如AES/ECB/PKCS5Padding)。
+ * @return 加密后的数据。
+ * @throws NoSuchPaddingException 如果指定的填充模式不被支持。
+ * @throws NoSuchAlgorithmException 如果指定的加密算法不被支持。
+ * @throws InvalidKeyException 如果密钥无效。
+ * @throws IllegalBlockSizeException 如果加密后数据的块大小不正确。
+ * @throws BadPaddingException 如果加密数据的填充不正确。
+ */
+private static byte[] encryptByType(byte[] data, String type, String key, String algorithm) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
+    // 创建AES加密算法实例
+    Cipher cipher = Cipher.getInstance(algorithm);
+
+    // 创建密钥规则
+    SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), type);
+
+    // 初始化加密模式
+    cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
+
+    // 执行加密操作
+    return cipher.doFinal(data);
+}
 
-    private static byte[] encryptByType(byte[] data, String type, String key, String algorithm) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
-// 创建AES加密算法实例
-        Cipher cipher = Cipher.getInstance(algorithm);
-
-        // 创建密钥规则
-        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), type);
-
-        // 初始化加密模式
-        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
-
-        // 执行加密操作
-        return cipher.doFinal(data);
-    }
-
-    private static byte[] decryptByType(byte[] encryptedData, String type, String key, String algorithm) throws Exception {
-        // 创建AES解密算法实例
-        Cipher cipher = Cipher.getInstance(algorithm);
-
-        // 创建密钥规则
-        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), type);
-
-        // 初始化解密模式
-        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
-
-        // 执行解密操作
-        byte[] decryptedBytes = cipher.doFinal(encryptedData);
-
-        // 将解密后的字节数组转换为字符串
-
-        return decryptedBytes;
-    }
-
-    private static byte[] doFinalByKeyStr(int mode, byte[] data, String keyStr, String type, String algorithm, int opmode) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
-
-        //根据转换的名称获取密码对象Cipher(转换的名称:算法/工作模式/填充模式)
-        Cipher cipher = Cipher.getInstance(algorithm);
-
-        switch (mode) {
-            case 1 -> {
-                //根据PKCS8编码密钥规范产生私钥对象
-                PrivateKey privateKey = getPrivateKey(keyStr, checkType(type));
-                //用私钥初始化此Cipher对象(解密模式)
-                cipher.init(opmode, privateKey);
-            }
-            default -> {
-                //根据PKCS8编码密钥规范产生私钥对象
-                PublicKey publicKey = getPublicKey(keyStr, checkType(type));
-                //用私钥初始化此Cipher对象(解密模式)
-                cipher.init(opmode, publicKey);
-            }
-        }
+/**
+ * 根据指定的解密类型、密钥和算法对加密数据进行解密。
+ *
+ * @param encryptedData 加密的数据。
+ * @param type 解密算法的类型(如AES)。
+ * @param key 解密使用的密钥。
+ * @param algorithm 解密算法的名称(如AES/ECB/PKCS5Padding)。
+ * @return 解密后的数据。
+ * @throws Exception 如果解密过程中发生错误。
+ */
+private static byte[] decryptByType(byte[] encryptedData, String type, String key, String algorithm) throws Exception {
+    // 创建AES解密算法实例
+    Cipher cipher = Cipher.getInstance(algorithm);
+
+    // 创建密钥规则
+    SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), type);
+
+    // 初始化解密模式
+    cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
+
+    // 执行解密操作
+    byte[] decryptedBytes = cipher.doFinal(encryptedData);
+
+    // 将解密后的字节数组转换为字符串
+    return decryptedBytes;
+}
 
-        return cipher.doFinal(data);
-    }
+/**
+ * 根据模式、数据、密钥字符串、类型和算法执行加密或解密操作。
+ *
+ * @param mode 模式标识,1代表加密,其他代表解密。
+ * @param data 待处理的数据。
+ * @param keyStr 密钥字符串。
+ * @param type 密钥类型(如AES)。
+ * @param algorithm 算法名称(如AES/ECB/PKCS5Padding)。
+ * @param opmode Cipher操作模式,如ENCRYPT_MODE或DECRYPT_MODE。
+ * @return 处理后的数据。
+ * @throws NoSuchAlgorithmException 如果指定的加密算法不被支持。
+ * @throws InvalidKeySpecException 如果密钥规范无效。
+ * @throws NoSuchPaddingException 如果指定的填充模式不被支持。
+ * @throws InvalidKeyException 如果密钥无效。
+ * @throws IllegalBlockSizeException 如果加密后数据的块大小不正确。
+ * @throws BadPaddingException 如果加密数据的填充不正确。
+ */
+private static byte[] doFinalByKeyStr(int mode, byte[] data, String keyStr, String type, String algorithm, int opmode) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
+
+    //根据转换的名称获取密码对象Cipher(转换的名称:算法/工作模式/填充模式)
+    Cipher cipher = Cipher.getInstance(algorithm);
+
+    if (mode == 1) {//根据PKCS8编码密钥规范产生私钥对象
+        PrivateKey privateKey = getPrivateKey(keyStr, checkType(type));
+        //用私钥初始化此Cipher对象(解密模式)
+        cipher.init(opmode, privateKey);
+    } else {//根据PKCS8编码密钥规范产生私钥对象
+        PublicKey publicKey = getPublicKey(keyStr, checkType(type));
+        //用私钥初始化此Cipher对象(解密模式)
+        cipher.init(opmode, publicKey);
+    }
+
+    return cipher.doFinal(data);
+}
 
 
+    /**
+     * 通过Base64编码的字符串获取公钥对象。
+     *
+     * @param publicKeyStr Base64编码的公钥字符串
+     * @param type 密钥算法类型(如RSA)
+     * @return 公钥对象
+     * @throws NoSuchAlgorithmException 当指定的算法不可用时抛出
+     * @throws InvalidKeySpecException 当提供的密钥规范不适合时抛出
+     */
     private static PublicKey getPublicKey(String publicKeyStr, String type) throws NoSuchAlgorithmException, InvalidKeySpecException {
+        // 解码Base64编码的公钥字符串
         X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyStr.getBytes()));
+        // 获取对应算法的KeyFactory
         KeyFactory keyFactory = KeyFactory.getInstance(type);
+        // 生成公钥对象
         return keyFactory.generatePublic(keySpec);
     }
 
+    /**
+     * 通过Base64编码的字符串获取私钥对象。
+     *
+     * @param privateKeyStr Base64编码的私钥字符串
+     * @param type 密钥算法类型(如RSA)
+     * @return 私钥对象
+     * @throws NoSuchAlgorithmException 当指定的算法不可用时抛出
+     * @throws InvalidKeySpecException 当提供的密钥规范不适合时抛出
+     */
     private static PrivateKey getPrivateKey(String privateKeyStr, String type) throws NoSuchAlgorithmException, InvalidKeySpecException {
+        // 解码Base64编码的私钥字符串
         PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyStr.getBytes()));
+        // 获取对应算法的KeyFactory
         KeyFactory keyFactory = KeyFactory.getInstance(type);
+        // 生成私钥对象
         return keyFactory.generatePrivate(keySpec);
     }
 
-
+    /**
+     * 对数据进行签名。
+     *
+     * @param data 待签名的数据
+     * @param priKey 私钥,Base64编码
+     * @param type 密钥算法类型(如RSA)
+     * @param algorithm 签名算法(如SHA256withRSA)
+     * @return 签名结果,Base64编码
+     * @throws Exception 当签名过程出错时抛出
+     */
     private static String sign(byte[] data, byte[] priKey, String type, String algorithm) throws Exception {
-        //创建PKCS8编码密钥规范
+        // 创建PKCS8编码密钥规范
         PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKey);
-        //返回转换指定算法的KeyFactory对象
+        // 生成私钥对象
         KeyFactory keyFactory = KeyFactory.getInstance(checkSingType(type));
-        //根据PKCS8编码密钥规范产生私钥对象
         PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
-        //用指定算法产生签名对象Signature
+        // 创建签名对象
         Signature signature = Signature.getInstance(algorithm);
-        //用私钥初始化签名对象Signature
+        // 用私钥初始化签名对象
         signature.initSign(privateKey);
-        //将待签名的数据传送给签名对象(须在初始化之后)
+        // 更新签名内容
         signature.update(data);
-        //返回签名结果字节数组
+        // 生成签名结果
         byte[] sign = signature.sign();
-        //返回Base64编码后的字符串
+        // 返回Base64编码后的签名结果
         return Base64.getEncoder().encodeToString(sign);
     }
 
-
+    /**
+     * 验证签名是否有效。
+     *
+     * @param data 待验证的数据
+     * @param sign 签名数据,Base64编码
+     * @param pubKey 公钥,Base64编码
+     * @param type 密钥算法类型(如RSA)
+     * @param algorithm 签名算法(如SHA256withRSA)
+     * @return 标识签名是否有效的布尔值
+     * @throws Exception 当验证过程出错时抛出
+     */
     private static boolean verify(byte[] data, byte[] sign, byte[] pubKey, String type, String algorithm) throws Exception {
-        //返回转换指定算法的KeyFactory对象
+        // 生成公钥对象
         KeyFactory keyFactory = KeyFactory.getInstance(checkSingType(type));
-        //创建X509编码密钥规范
-        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKey);
-        //根据X509编码密钥规范产生公钥对象
-        PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
-        //用指定算法产生签名对象Signature
+        PublicKey publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(pubKey));
+        // 创建签名对象
         Signature signature = Signature.getInstance(algorithm);
-        //用公钥初始化签名对象,用于验证签名
+        // 用公钥初始化签名对象,用于验证签名
         signature.initVerify(publicKey);
-        //更新签名内容
+        // 更新签名内容
         signature.update(data);
-        //得到验证结果
+        // 验证签名结果
         return signature.verify(sign);
     }
 
-
+    /**
+     * 检查给定的加密类型是否为RSA,如果是,则返回大写的RSA,如果不是或为空,则默认返回RSA。
+     *
+     * @param type 加密类型字符串
+     * @return 经过检查后的加密类型字符串
+     */
     private static String checkType(String type) {
-        if (Objects.isNull(type)) return "RSA";
+        if (Objects.isNull(type)) return "RSA"; // 如果类型为空,直接返回RSA
         if (type.equalsIgnoreCase("RSA")) {
-            return type.toUpperCase();
+            return type.toUpperCase(); // 如果类型是RSA,返回大写的RSA
         }
-        return "RSA";
+        return "RSA"; // 如果不是RSA,则返回RSA
     }
 
+    /**
+     * 检查给定的签名类型是否支持,支持的类型有RSA和DSA,如果是支持的类型之一,则返回大写的类型名,如果不是或为空,则默认返回RSA。
+     *
+     * @param type 签名类型字符串
+     * @return 经过检查后的签名类型字符串
+     */
     private static String checkSingType(String type) {
-        if (Objects.isNull(type)) return "RSA";
-        switch (type.toUpperCase()) {
-            case "RSA", "DSA" -> {
-                return type.toUpperCase();
-            }
-            default -> {
-                return "RSA";
-            }
+        if (Objects.isNull(type)) return "RSA"; // 如果类型为空,直接返回RSA
+        // 将输入转换为大写进行匹配
+        if (type.equalsIgnoreCase("RSA") || type.equalsIgnoreCase("DSA")) {
+            return type.toUpperCase(); // 如果是RSA或DSA,返回大写的类型名
         }
+        return "RSA"; // 如果不是RSA或DSA,则返回RSA
     }
 
+    /**
+     * 检查给定的SHA算法是否支持,支持的算法有SHA-1, SHA-224, SHA-256, SHA-384和SHA-512,如果是支持的算法之一,则返回大写的算法名,如果不是或为空,则默认返回SHA-256。
+     *
+     * @param algorithm 加密算法字符串
+     * @return 经过检查后的加密算法字符串
+     */
     private static String checkSHAAlgorithm(String algorithm) {
-        if (Objects.isNull(algorithm)) return "SHA-256";
-        switch (algorithm.toUpperCase()) {
-            case "SHA-256", "SHA-1", "SHA-224", "SHA-384", "SHA-512" -> {
-                return algorithm.toUpperCase();
-            }
-            default -> {
-                return "SHA-256";
-            }
+        if (algorithm == null || algorithm.isEmpty()) return "SHA-256"; // 如果算法为空或者为空字符串,直接返回SHA-256
+        // 将输入转换为大写进行匹配
+        if (algorithm.equalsIgnoreCase("SHA-256") || algorithm.equalsIgnoreCase("SHA-1") || algorithm.toUpperCase().equals("SHA-224") || algorithm.toUpperCase().equals("SHA-384") || algorithm.toUpperCase().equals("SHA-512")) {
+            return algorithm.toUpperCase(); // 如果是支持的SHA算法之一,返回大写的算法名
         }
+        return "SHA-256"; // 如果不是支持的SHA算法,则返回SHA-256
     }
+
 }

+ 262 - 50
src/main/java/com/scbfkj/uni/library/DataFormatUtil.java

@@ -5,7 +5,6 @@ import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.LongNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.fasterxml.jackson.databind.node.TextNode;
 import com.fasterxml.jackson.dataformat.xml.XmlMapper;
@@ -24,107 +23,223 @@ import java.util.*;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.stream.Collectors;
 
+/**
+ * 定义了与日期时间格式化和JSON/XML序列化与反序列化相关的静态常量和工具。
+ */
 public final class DataFormatUtil {
-    private static final AtomicReference<ObjectMapper> objectMapper = new AtomicReference<>();
-    private static final AtomicReference<XmlMapper> xmlMapper = new AtomicReference<>();
 
+    // 原子引用,用于线程安全地存储和访问 ObjectMapper 实例,用于JSON的序列化和反序列化
+    private static final AtomicReference<ObjectMapper> OBJECT_MAPPER = new AtomicReference<>();
+
+    // 原子引用,用于线程安全地存储和访问 XmlMapper 实例,用于XML的序列化和反序列化
+    private static final AtomicReference<XmlMapper> XML_MAPPER = new AtomicReference<>();
+
+    // 本地日期时间格式字符串,用于日期时间的字符串表示和解析
     private static final String LOCAL_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
-    private static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(LOCAL_DATETIME_PATTERN);
 
+    // 使用定义的日期时间格式创建的 DateTimeFormatter 实例,用于日期时间的格式化和解析
+    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(LOCAL_DATETIME_PATTERN);
 
+    /**
+     * 将任意对象转换为JsonNode。
+     *
+     * @param source 需要转换的对象。
+     * @return 转换后的JsonNode。
+     * @throws JsonProcessingException 当转换过程中发生错误时抛出。
+     */
     public static JsonNode toJsonNode(Object source) throws JsonProcessingException {
         return getObjectMapper().readTree(toString(source));
     }
 
+    /**
+     * 将JSON字符串转换为指定类型的Java对象。
+     *
+     * @param source 需要转换的JSON字符串。
+     * @param clazz  需要转换成的目标对象类型。
+     * @param <T>    目标对象的类型。
+     * @return 转换后的Java对象。
+     * @throws JsonProcessingException 当转换过程中发生错误时抛出。
+     */
     public static <T> T stringToBean(String source, Class<T> clazz) throws JsonProcessingException {
         return getObjectMapper().readValue(source, clazz);
     }
 
+    /**
+     * 将JSON字符串转换为Map对象。
+     * 这是一个通用方法,用于将JSON字符串解析为Map格式,方便对JSON数据进行键值对访问。
+     *
+     * @param source 需要转换的JSON字符串。
+     * @return 转换后的Map对象。
+     * @throws JsonProcessingException 当转换过程中发生错误时抛出。
+     */
     public static Map<?, ?> stringToMap(String source) throws JsonProcessingException {
         return stringToBean(source, Map.class);
     }
 
+    /**
+     * 将JSON字符串转换为ObjectNode。
+     *
+     * @param source 需要转换的JSON字符串。
+     * @return 转换后的ObjectNode,是一个可编辑的JSON对象节点。
+     * @throws JsonProcessingException 当转换过程中发生错误时抛出。
+     */
     public static ObjectNode stringToObjectNode(String source) throws JsonProcessingException {
         return getObjectMapper().readValue(source, ObjectNode.class);
     }
 
+    /**
+     * 将JSON字符串转换为ArrayNode。
+     *
+     * @param source 需要转换的JSON字符串。
+     * @return 转换后的ArrayNode,是一个可编辑的JSON数组节点。
+     * @throws JsonProcessingException 当转换过程中发生错误时抛出。
+     */
     public static ArrayNode stringToArrayNode(String source) throws JsonProcessingException {
         return getObjectMapper().readValue(source, ArrayNode.class);
     }
 
+    /**
+     * 将各种类型的对象转换为字符串表示。
+     *
+     * @param source 需要转换的对象。可以是任意类型,包括String、Number、TextNode、JsonNode、LocalDate、LocalDateTime等。
+     * @return 如果对象为null,返回null;如果是字符串或数字类型,返回其本身字符串形式;如果是TextNode,返回其asText方法的结果;
+     * 如果是JsonNode,返回其toString方法的结果;如果是LocalDate或LocalDateTime,返回其格式化后的字符串;
+     * 对于其他类型,尝试使用Jackson的ObjectMapper将其转换为字符串,如果转换失败,则返回对象的toString方法结果。
+     */
     public static String toString(Object source) {
+        // 检查对象是否为null
         if (Objects.isNull(source)) {
             return null;
         }
+        // 直接处理字符串或数值类型
         if (source instanceof String || source instanceof Number) {
             return source.toString();
         }
+        // 处理JSON节点类型
         if (source instanceof TextNode jsonNode) {
             return jsonNode.asText();
         }
         if (source instanceof JsonNode jsonNode) {
             return jsonNode.toString();
         }
+        // 处理日期时间类型
         if (source instanceof LocalDate result) {
-            return result.format(dateTimeFormatter);
+            return result.format(DATE_TIME_FORMATTER);
         }
         if (source instanceof LocalDateTime result) {
-            return result.format(dateTimeFormatter);
+            return result.format(DATE_TIME_FORMATTER);
         }
+        // 尝试使用Jackson ObjectMapper处理其他类型
         try {
             return getObjectMapper().writeValueAsString(source);
         } catch (JsonProcessingException e) {
+            // ObjectMapper转换失败时,回退到使用对象的toString方法
             return source.toString();
         }
     }
 
+    /**
+     * 将不同类型的日期对象转换为LocalDate。
+     *
+     * @param dateObj 可以是String、LocalDate或java.util.Date类型的日期对象。
+     *                如果是String类型,应符合LocalDate的解析格式;
+     *                如果是LocalDate类型,直接返回;
+     *                如果是Date类型,将转换为"yyyy-MM-dd HH:dd:ss"格式的字符串,
+     *                然后解析为LocalDate(时间部分用"T"分隔)。
+     * @return 返回转换后的LocalDate对象,如果输入类型不支持,则返回null。
+     */
     public static LocalDate toDate(Object dateObj) {
+        // 字符串类型日期转换
         if (dateObj instanceof String str) {
             return LocalDate.parse(str);
+            // LocalDate类型直接返回
         } else if (dateObj instanceof LocalDate date) {
             return date;
+            // java.util.Date类型转换
+        } else if (dateObj instanceof LocalDateTime date) {
+            return date.toLocalDate();
+            // java.util.Date类型转换
         } else if (dateObj instanceof Date date) {
             SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:dd:ss");
             String formatDate = simpleDateFormat.format(date);
+            // 将Date类型转换为符合LocalDate解析格式的字符串
             return LocalDate.parse(formatDate.replace(" ", "T"));
         } else {
+            // 不支持的类型返回null
             return null;
         }
     }
 
+    /**
+     * 将不同类型的日期时间对象转换为LocalDateTime。
+     *
+     * @param dateTimeObj 可以是String、LocalDate、LocalDateTime或java.util.Date类型的日期时间对象。
+     *                    如果是String类型,应符合ISO 8601日期时间格式,可以直接解析为LocalDateTime。
+     *                    如果是LocalDate类型,将转换为该日期的午夜时间(00:00)的LocalDateTime。
+     *                    如果是LocalDateTime类型,直接返回原对象。
+     *                    如果是java.util.Date类型,将根据指定的格式转换为String,然后解析为LocalDateTime。
+     * @return 返回转换后的LocalDateTime对象,如果输入对象类型不支持转换,则返回null。
+     */
     public static LocalDateTime toDateTime(Object dateTimeObj) {
         if (dateTimeObj instanceof String str) {
+            // 直接解析字符串为LocalDateTime
             return LocalDateTime.parse(str);
+        } else if (dateTimeObj instanceof LocalDate date) {
+            // 将LocalDate转换为当日午夜的LocalDateTime
+            return date.atTime(0, 0);
         } else if (dateTimeObj instanceof LocalDateTime dateTime) {
+            // 已是LocalDateTime类型,直接返回
             return dateTime;
         } else if (dateTimeObj instanceof Date date) {
+            // 将java.util.Date转换为指定格式的字符串,再解析为LocalDateTime
             SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:dd:ss");
             String formatDate = simpleDateFormat.format(date);
             return LocalDateTime.parse(formatDate.replace(" ", "T"));
         } else {
+            // 不支持的类型,返回null
             return null;
         }
     }
-
+    /**
+     * 将日期字符串转换为LocalDate对象。
+     *
+     * @param dateStr 代表日期的字符串,应符合LocalDate的解析格式。
+     * @return 返回解析后的LocalDate对象。
+     */
     public static LocalDate stringToDate(String dateStr) {
         return LocalDate.parse(dateStr);
     }
 
+    /**
+     * 将日期时间字符串转换为LocalDateTime对象。
+     *
+     * @param dateTimeStr 代表日期时间的字符串,应符合LocalDateTime的解析格式。
+     * @return 返回解析后的LocalDateTime对象。
+     */
     public static LocalDateTime stringToDateTime(String dateTimeStr) {
         return LocalDateTime.parse(dateTimeStr);
     }
-
+    /**
+     * 将给定的对象转换为列表形式。
+     *
+     * @param value 需要转换的对象。可以是可迭代对象、数组、字符串或者单个对象。
+     * @return 返回转换后的对象列表。如果输入为null,则返回null。如果输入是可迭代对象或数组,则返回包含这些元素的列表。
+     *         如果输入是JSON字符串,则尝试解析为对象列表。对于非可迭代、非数组、非字符串的单个对象,直接返回包含该对象的列表。
+     */
     public static List toList(Object value) {
         if (Objects.isNull(value)) {
             return null;
         }
+        // 处理可迭代对象,如集合等
         if (value instanceof Iterable<?> iterable) {
             ArrayList<Object> result = new ArrayList<>();
             iterable.forEach(result::add);
             return result;
         }
+        // 处理数组类型,包括Java数组和JSON数组(通过将JSON字符串解析为对象列表)
         if (value.getClass().isArray()) {
             return Arrays.stream(((Object[]) value)).map(it -> {
+                // 特殊处理JsonNode类型,将其转换为字符串
                 if (it instanceof JsonNode) {
                     return it.toString();
                 } else {
@@ -132,6 +247,7 @@ public final class DataFormatUtil {
                 }
             }).toList();
         }
+        // 处理字符串类型,尝试将字符串解析为对象列表,失败则将字符串作为单个元素返回
         if (value instanceof String) {
             try {
                 return getObjectMapper().readValue(value.toString(), List.class);
@@ -139,120 +255,188 @@ public final class DataFormatUtil {
                 return Collections.singletonList(value);
             }
         }
+        // 对于其他类型,直接返回包含该对象的列表
         return Collections.singletonList(value);
     }
 
+    /**
+     * 将给定的对象转换为对象数组。
+     * 如果输入值为null,返回null。
+     * 如果输入值已经是数组,则直接返回该数组。
+     * 如果输入值不是数组,将尝试将其转换为列表,然后返回该列表的数组形式。
+     *
+     * @param value 需要转换的对象。可以是任意类型,包括数组。
+     * @return 对象数组。如果输入为null,则返回null;如果输入为非数组类型,则返回其列表的数组形式。
+     */
     public static Object[] toArray(Object value) {
+        // 检查输入值是否为null
         if (Objects.isNull(value)) {
             return null;
         }
+        // 判断输入是否为数组类型
         if (value.getClass().isArray()) {
             return (Object[]) value;
         }
+        // 将非数组类型转换为列表,然后转换为数组返回
         return Objects.requireNonNull(toList(value)).toArray();
     }
 
+    /**
+     * 将给定的对象转换为Map形式。
+     * 如果对象本身就是Map类型,则直接返回该对象。
+     * 否则,尝试将对象转换为字符串,然后将该字符串转换为Map。
+     * 如果字符串转换失败,将尝试其他格式的解析。
+     *
+     * @param value 需要转换的对象。
+     * @return 转换后的Map对象,如果无法转换则返回null。
+     */
     public static Map<?, ?> toMap(Object value) {
         if (Objects.isNull(value)) {
             return null;
         }
+        // 如果value本身就是Map类型,则直接返回
         if (value instanceof Map<?, ?> map) {
             return map;
         }
         String str = DataFormatUtil.toString(value);
         try {
+            // 尝试将对象字符串转换为Map
             return DataFormatUtil.stringToMap(str);
         } catch (JsonProcessingException ignored) {
             try {
+                // 如果上面的转换失败,尝试另一种方式转换字符串为Map
                 return stringToMap(str);
             } catch (JsonProcessingException e) {
                 try {
+                    // 如果仍然失败,尝试将字符串解析为JSON节点,并放入Map中
                     HashMap<Object, Object> data = new HashMap<>();
                     data.put("root", toJsonNode(str));
                     return data;
                 } catch (JsonProcessingException ex) {
-
+                    // JSON处理异常,此处不做处理,将异常忽略
                 }
             }
         }
+        // 所有尝试都失败后,将原对象直接放入Map的root键中返回
         HashMap<Object, Object> data = new HashMap<>();
         data.put("root", value);
         return data;
     }
 
-    public static ObjectMapper getObjectMapper() {
-        synchronized (objectMapper) {
-            if (objectMapper.get() == null) {
-                ObjectMapper objectMapper1 = new ObjectMapper();
-                objectMapper1.registerModule(new Jdk8Module());
-                //为jackjson注册序列化提供能力的对象
-                JavaTimeModule javaTimeModule = new JavaTimeModule();
-//系列化时间格式化
-                javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-                javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
-//反序列化时间格式化
-                javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-                javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
-
-                objectMapper1.registerModule(javaTimeModule);
-                objectMapper1.setSerializationInclusion(JsonInclude.Include.ALWAYS);
-                objectMapper.set(objectMapper1);
-            }
+/**
+ * 获取一个配置了特定模块和时间格式的ObjectMapper实例。
+ * 此方法确保了线程安全,并且只会创建一个ObjectMapper实例,之后的调用将返回相同的实例。
+ *
+ * @return 配置好的ObjectMapper实例,可用于进行JSON的序列化和反序列化操作。
+ */
+public static ObjectMapper getObjectMapper() {
+    synchronized (OBJECT_MAPPER) { // 确保线程安全,在访问OBJECT_MAPPER时进行同步
+        if (OBJECT_MAPPER.get() == null) { // 如果OBJECT_MAPPER还未被初始化,则进行初始化
+            ObjectMapper objectMapper1 = new ObjectMapper(); // 创建ObjectMapper实例
+            objectMapper1.registerModule(new Jdk8Module()); // 注册JDK 8模块以支持新数据类型
+
+            // 注册Java时间模块并自定义序列化和反序列化的格式
+            JavaTimeModule javaTimeModule = new JavaTimeModule();
+            javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+            javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+            javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+            javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+
+            objectMapper1.registerModule(javaTimeModule); // 将Java时间模块注册到ObjectMapper
+            objectMapper1.setSerializationInclusion(JsonInclude.Include.ALWAYS); // 设置序列化时总是包含值,避免null值问题
+            OBJECT_MAPPER.set(objectMapper1); // 将配置好的ObjectMapper实例设置到ThreadLocal中
         }
-        return objectMapper.get();
     }
+    return OBJECT_MAPPER.get(); // 返回配置好的ObjectMapper实例
+}
 
-    public static XmlMapper getXmlMapper() {
-        synchronized (xmlMapper) {
-            if (xmlMapper.get() == null) {
-                XmlMapper objectMapper1 = new XmlMapper();
-                objectMapper1.registerModule(new Jdk8Module());
-                //为jackjson注册序列化提供能力的对象
-                JavaTimeModule javaTimeModule = new JavaTimeModule();
-//系列化时间格式化
-                javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-                javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
-//反序列化时间格式化
-                javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
-                javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
-
-                objectMapper1.registerModule(javaTimeModule);
-                objectMapper1.setSerializationInclusion(JsonInclude.Include.ALWAYS);
-                xmlMapper.set(objectMapper1);
-            }
+
+/**
+ * 获取一个配置好的XmlMapper实例。
+ * 此方法使用单例模式确保全局仅有一个XmlMapper实例被创建并使用。
+ * 配置包括:注册Jdk8Module以支持Java 8日期时间API的序列化和反序列化,
+ * 自定义LocalDateTime和LocalDate的序列化和反序列化格式。
+ *
+ * @return 配置好的XmlMapper实例。
+ */
+public static XmlMapper getXmlMapper() {
+    synchronized (XML_MAPPER) { // 确保线程安全地创建单例
+        if (XML_MAPPER.get() == null) { // 只有在XmlMapper实例未被创建时才执行以下逻辑
+            XmlMapper objectMapper1 = new XmlMapper();
+            objectMapper1.registerModule(new Jdk8Module()); // 注册Jdk8Module
+
+            // 配置JavaTimeModule以支持Java 8日期时间的序列化和反序列化
+            JavaTimeModule javaTimeModule = new JavaTimeModule();
+            // 序列化时间格式化配置
+            javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+            javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+            // 反序列化时间格式化配置
+            javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+            javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+
+            objectMapper1.registerModule(javaTimeModule); // 注册JavaTimeModule
+            objectMapper1.setSerializationInclusion(JsonInclude.Include.ALWAYS); // 设置序列化时总是包含值
+
+            XML_MAPPER.set(objectMapper1); // 将创建的XmlMapper实例设置到ThreadLocal中
         }
-        return xmlMapper.get();
     }
-
+    return XML_MAPPER.get(); // 返回配置好的XmlMapper实例
+}
+    /**
+     * 将XML字符串列表转换为对应的JSON字符串列表。
+     * @param xmls XML字符串列表,每个字符串代表一个XML文档。
+     * @return 转换后的JSON字符串列表,每个字符串对应输入XML列表中的一个XML文档的JSON表示。
+     */
     public static List<String> xmltojson(List<String> xmls) {
+        // 使用Stream处理xmls列表,将每个XML字符串转换为JSON字符串
         return xmls.stream().map(xml -> {
             Object json = null;
             try {
+                // 将XML字符串解析为JSON对象
                 json = getXmlMapper().readValue(xml, Object.class);
+                // 将JSON对象转换为字符串
                 return getObjectMapper().writeValueAsString(json);
             } catch (JsonProcessingException e) {
+                // 处理JSON处理异常,转换为运行时异常
                 throw new RuntimeException(e);
             }
 
         }).collect(Collectors.toList());
     }
 
+    /**
+     * 将单个XML字符串转换为对应的JSON字符串。
+     * @param xml XML字符串,代表一个XML文档。
+     * @return 转换后的JSON字符串,表示输入XML字符串的JSON形式。
+     * @throws JsonProcessingException 当JSON处理过程中发生错误时抛出。
+     */
     public static String xml2json(String xml) throws JsonProcessingException {
+        // 将XML字符串解析为JSON对象
         Object json = getXmlMapper().readValue(xml, Object.class);
-
+        // 将JSON对象转换为字符串
         return getObjectMapper().writeValueAsString(json);
     }
 
+    /**
+     * 将类型B的数据转换为Map格式。
+     *
+     * @param datas 包含类型B数据的字符串列表,每个字符串代表一条数据,数据之间通过特定字符分割。
+     * @return 返回一个List,每个元素是一个Map,其中Map的键是数据的类型标识,值是一个List,包含对应类型的所有数据详细信息。
+     */
     public static List<Map<String, List<List<String>>>> typeBtoMap(List<String> datas) {
         return datas.stream().map(it -> {
+            // 初始化一个空的Map用于存储解析后的数据
             Map<String, List<List<String>>> data = new HashMap<>();
+            // 分割字符串以获取单个数据项
             String[] split = it.split("[.|(\\r)?\\n]");
             for (String s : split) {
+                // 解析每个数据项,并忽略长度不为1的类型标识
                 String[] cells = s.split("/");
                 String cell = cells[0];
                 if (cell.length() != 1) {
                     continue;
                 }
+                // 将解析出的数据项添加到对应的Map键下
                 List<String> ds = new ArrayList<>(Arrays.asList(cells).subList(1, cells.length));
                 if (data.containsKey(cell)) {
                     data.get(cell).add(ds);
@@ -262,6 +446,7 @@ public final class DataFormatUtil {
                     }});
                 }
             }
+            // 根据特定标签识别数据类型,并添加到Map中
             if (it.contains("BSM") && it.contains("ENDBSM")) {
                 data.put("type", new ArrayList<>() {{
                     add(new ArrayList<>() {{
@@ -279,65 +464,92 @@ public final class DataFormatUtil {
         }).toList();
     }
 
+    /**
+     * 检查提供的字符串是否是有效的JSON格式。
+     *
+     * @param data 需要检查的字符串。
+     * @return 返回一个布尔值,如果字符串是有效的JSON,则返回true;否则返回false。
+     */
     public static boolean isJson(String data) {
         try {
-            JsonNode jsonNode = getObjectMapper().readTree(data);
+            // 尝试使用Jackson的ObjectMapper解析输入字符串为JSON节点,如成功则字符串是有效的JSON
+            getObjectMapper().readTree(data);
             return true;
         } catch (Exception e) {
+            // 如果解析过程中发生异常,则输入字符串不是有效的JSON
             return false;
         }
     }
 
+    /**
+     * 将给定的对象转换为指定的类型。
+     *
+     * @param node 需要转换的对象,可以是任意类型。
+     * @param parameterType 指定的目标类型,使用泛型参数来指定。
+     * @return 转换后的对象,其类型为T。如果转换失败或node为null,则返回null。
+     */
     public static <T> T castType(Object node, Class<T> parameterType) {
 
+        // 检查输入对象是否为null
         if (node == null) {
             return null;
         }
         String type = parameterType.getSimpleName();
         Object result = null;
+        // 根据目标类型进行不同的转换处理
         if ("String".equalsIgnoreCase(type)) {
+            // 字符串类型转换处理
             if (node instanceof JsonNode jsonNode) {
                 result = jsonNode.asText();
             } else {
                 result = node.toString();
             }
         } else if ("List".equalsIgnoreCase(type) || "Collection".equalsIgnoreCase(type)) {
+            // 集合类型转换处理
             result = DataFormatUtil.toList(node);
         } else if ("Array".equalsIgnoreCase(type)) {
+            // 数组类型转换处理
             result = DataFormatUtil.toArray(node);
         } else if ("Map".equalsIgnoreCase(type)) {
+            // 映射类型转换处理
             result = DataFormatUtil.toMap(node);
         } else if ("Long".equalsIgnoreCase(type)) {
+            // 长整型转换处理
             if (node instanceof JsonNode jsonNode) {
                 result = jsonNode.asLong();
             } else {
                 result = Long.valueOf(node.toString());
             }
         } else if ("Integer".equalsIgnoreCase(type)) {
+            // 整型转换处理
             if (node instanceof JsonNode jsonNode) {
                 result = jsonNode.asInt();
             } else {
                 result = Integer.valueOf(node.toString());
             }
         } else if ("Double".equalsIgnoreCase(type)) {
+            // 双精度浮点型转换处理
             if (node instanceof JsonNode jsonNode) {
                 result = jsonNode.doubleValue();
             } else {
                 result = Double.valueOf(node.toString());
             }
         } else if ("Float".equalsIgnoreCase(type)) {
+            // 单精度浮点型转换处理
             if (node instanceof JsonNode jsonNode) {
                 result = jsonNode.floatValue();
             } else {
                 result = Float.valueOf(node.toString());
             }
         } else if ("Boolean".equalsIgnoreCase(type)) {
+            // 布尔型转换处理
             if (node instanceof JsonNode jsonNode) {
                 result = jsonNode.asBoolean();
             } else {
                 result = Boolean.valueOf(node.toString());
             }
         }
+        // 泛型转换返回
         return (T) result;
     }
 }

+ 21 - 3
src/main/java/com/scbfkj/uni/library/EmailUtil.java

@@ -7,31 +7,49 @@ import com.scbfkj.uni.system.Config;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
-
+/**
+ * 邮件工具类,提供发送邮件的 方法。
+ */
 public class EmailUtil {
 
+    // 数据库实例
     private static final DataBase DATA_BASE = new DataBase();
 
 
+    /**
+     * 通过数据源发送邮件。
+     *
+     * @param dataSourceId 数据源ID,用于查询邮件发送配置。
+     * @param to 收件人邮箱。
+     * @param subject 邮件主题。
+     * @param content 邮件内容。
+     * @return 返回操作结果,成功则包含成功信息,失败则包含失败原因。
+     * @throws Exception 抛出异常,处理邮件发送过程中的错误。
+     */
     public Map<String, Object> sendEmailByDataSource(String dataSourceId, String to, String subject, String content) throws Exception {
 
-
+        // 检查收件人邮箱是否为空
         if(Objects.isNull(to)){
             return UniReturnUtil.fail("邮箱不能为空");
         }
 
+        // 从数据库中查询对应数据源配置
         Optional<Map<String, Object>> datasourceOpt = DATA_BASE.query(Config.getCenterConnectionStr(), "select * from datasource where datasourceid=?", dataSourceId).stream().findFirst();
 
+        // 数据源配置未找到时的处理
         if (datasourceOpt.isEmpty()) {
             return UniReturnUtil.fail("数据源没有找到");
         }
         Map<String, Object> dataSource = datasourceOpt.get();
+
+        // 配置邮件发送参数
         Map<?, ?> props = DataFormatUtil.toMap(dataSource.get("host"));
         String emailUsername = DataFormatUtil.toString(dataSource.get("username"));
         String emailPassword = DataFormatUtil.toString(dataSource.get("password"));
 
 
-        Email.sendEmail(props, emailUsername, emailPassword, to, subject, content);
+        // 发送邮件
+        Email.sendEmail((Map<String, Object>) props, emailUsername, emailPassword, to, subject, content);
         return UniReturnUtil.success("success");
     }
 

+ 36 - 9
src/main/java/com/scbfkj/uni/library/FileUtil.java

@@ -10,48 +10,75 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-
+/**
+ * 文件工具类,提供读取Excel文件到Map的方法。
+ */
 public class FileUtil {
 
-
+    /**
+     * 从Excel文件中读取数据到Map中。
+     * 每个Sheet页的数据被存储为一个List<List<String>>,其中外层List表示Sheet页的行,内层List表示行中的单元格数据。
+     * 所有Sheet页的数据以Sheet名称为键存储在一个Map中。
+     *
+     * @param file 要读取的Excel文件。
+     * @return 一个Map,键为Sheet名称,值为该Sheet页的数据,格式为List<List<String>>。
+     * @throws IOException 如果读取文件发生错误。
+     */
     public static Map<String, List<List<String>>> readExcelToMap(File file) throws IOException {
 
         try (FileInputStream fis = new FileInputStream(file)) {
+            // 通过FileInputStream读取文件内容,然后调用另个方法处理输入流
             return readExcelToMap(fis);
         }
     }
 
+    /**
+     * 从Excel的输入流中读取数据到Map中。
+     * 每个Sheet页的数据被存储为一个List<List<String>>,其中外层List表示Sheet页的行,内层List表示行中的单元格数据。
+     * 所有Sheet页的数据以Sheet名称为键存储在一个Map中。
+     *
+     * @param fis Excel文件的输入流。
+     * @return 一个Map,键为Sheet名称,值为该Sheet页的数据,格式为List<List<String>>。
+     * @throws IOException 如果读取文件发生错误。
+     */
     public static Map<String, List<List<String>>> readExcelToMap(InputStream fis) throws IOException {
         Map<String, List<List<String>>> dataMap = new HashMap<>();
 
         try (
-                Workbook workbook = WorkbookFactory.create(fis)) {
+                Workbook workbook = WorkbookFactory.create(fis)) { // 使用输入流创建Workbook对象
+            // 遍历所有Sheet页
             for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
-                Sheet sheet = workbook.getSheetAt(i);
+                Sheet sheet = workbook.getSheetAt(i); // 获取当前Sheet页
 
                 List<List<String>> sheetData = new ArrayList<>();
+                // 遍历所有行
                 for (int i2 = 0; i2 <= sheet.getLastRowNum(); i2++) {
                     List<String> rowData = new ArrayList<>();
-                    Row row = sheet.getRow(i2);
+                    Row row = sheet.getRow(i2); // 获取当前行
                     if (row == null) {
-
+                        // 如果行为空,则添加空行数据
                         sheetData.add(rowData);
                         continue;
                     }
+                    // 遍历当前行的所有单元格
                     for (int i1 = 0; i1 < row.getLastCellNum(); i1++) {
-                        Cell cell = row.getCell(i1);
+                        Cell cell = row.getCell(i1); // 获取当前单元格
                         if (cell == null) {
+                            // 如果单元格为空,则添加空单元格数据
                             rowData.add(null);
                             continue;
                         }
+                        // 获取单元格的字符串内容并添加到行数据中
                         rowData.add(cell.getStringCellValue());
                     }
-                    sheetData.add(rowData);
+                    sheetData.add(rowData); // 将行数据添加到Sheet数据中
                 }
 
+                // 将Sheet页的数据添加到结果Map中
                 dataMap.put(sheet.getSheetName(), sheetData);
             }
         }
-        return dataMap;
+        return dataMap; // 返回包含所有Sheet页数据的Map
     }
 }
+

+ 21 - 3
src/main/java/com/scbfkj/uni/library/IbmmqUtil.java

@@ -6,11 +6,25 @@ import com.ibm.msg.client.jakarta.wmq.compat.base.internal.MQEnvironment;
 import com.ibm.msg.client.jakarta.wmq.compat.base.internal.MQQueue;
 import com.ibm.msg.client.jakarta.wmq.compat.base.internal.MQQueueManager;
 
-public class IbmmqUtil {
 
+public class IbmmqUtil {
+    /**
+     * 获取指定队列的深度。
+     *
+     * @param host 主机名,IBM MQ 队列管理器所在的主机。
+     * @param port 端口号,IBM MQ 队列管理器监听的端口。
+     * @param ccsid CCSID(Character Set Identifier),指定字符集。
+     * @param queueManager 队列管理器名称。
+     * @param channel 与队列管理器通信的通道名称。
+     * @param queueName 需要查询深度的队列名称。
+     * @param username 连接队列管理器的用户名。
+     * @param password 连接队列管理器的用户密码。
+     * @return 队列的当前深度,如果发生异常则返回 -1。
+     */
     public static int getDepth(String host, int port, int ccsid, String queueManager, String channel, String queueName, String username, String password) {
         MQQueueManager qMgr = null;
         try {
+            // 设置IBM MQ环境参数
             MQEnvironment.hostname = host;
             MQEnvironment.port = port;
             MQEnvironment.CCSID = ccsid;
@@ -18,13 +32,16 @@ public class IbmmqUtil {
             MQEnvironment.userID = username;
             MQEnvironment.password = password;
 
+            // 连接到队列管理器
             qMgr = new MQQueueManager(queueManager);
+            // 获取队列对象,用于查询队列深度
             MQQueue queue = qMgr.accessQueue(queueName, MQC.MQOO_INQUIRE | MQC.MQOO_INPUT_SHARED);
-            return queue.getCurrentDepth();
+            return queue.getCurrentDepth(); // 返回队列当前深度
         } catch (MQException e) {
             e.printStackTrace();
-            return -1;
+            return -1; // 发生异常,返回-1
         } finally {
+            // 断开与队列管理器的连接
             if (qMgr != null) {
                 try {
                     qMgr.disconnect();
@@ -35,3 +52,4 @@ public class IbmmqUtil {
         }
     }
 }
+

+ 98 - 47
src/main/java/com/scbfkj/uni/library/ImageUtil.java

@@ -13,78 +13,129 @@ import java.io.InputStream;
 import java.security.SecureRandom;
 import java.util.Base64;
 
+    /**
+     * 图片工具类
+     */
 @Component
 public class ImageUtil {
 
+        // 图片宽度
+        private static final int WIDTH = 120;
+        // 图片高度
+        private static final int HEIGHT = 45;
+        // 图片格式
+        private static final String IMAGE_FORMAT = "JPG";
+        // 可用颜色数组
+        private static final Color[] COLORS = new Color[]{
+                new Color(0, 0, 255), // 蓝色
+                new Color(0, 255, 0), // 绿色
+                new Color(255, 0, 0)  // 红色
+        };
+        // 随机数生成器,用于生成随机数
+        private static final SecureRandom RANDOM = new SecureRandom();
+        // 资源模式解析器,用于解析资源路径
+        private static ResourcePatternResolver resourcePatternResolver;
+
+        /**
+         * 构造函数
+         *
+         * @param resourcePatternResolver 资源模式解析器,用于处理资源的解析
+         */
+        public ImageUtil(ResourcePatternResolver resourcePatternResolver) {
+            ImageUtil.resourcePatternResolver = resourcePatternResolver;
+        }
 
-    private static final int WIDTH = 120; // 图片宽度
-    private static final int HEIGHT = 45; // 图片高度
-    private static final String IMAGE_FORMAT = "JPG";
-    private static final Color[] COLORS = new Color[]{
-            new Color(0, 0, 255),
-            new Color(0, 255, 0),
-            new Color(255, 0, 0)
-    };
-    private static final SecureRandom RANDOM = new SecureRandom();
-    private static ResourcePatternResolver resourcePatternResolver;
 
-    public ImageUtil(ResourcePatternResolver resourcePatternResolver) {
-        ImageUtil.resourcePatternResolver = resourcePatternResolver;
-    }
 
 
+    /**
+     * 将给定的字符串转换为图片格式的Base64编码字符串。
+     *
+     * @param code 需要转换为图片的字符串。
+     * @return 图片的Base64编码字符串,该字符串可以直接嵌入HTML中显示图片。
+     * @throws IOException 当读写图片文件时发生错误。
+     * @throws FontFormatException 当字体格式不正确时抛出。
+     */
     public static String stringToImage(String code) throws IOException, FontFormatException {
+        // 使用try-with-resources语句自动关闭ByteArrayOutputStream
         try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
+            // 根据code创建图片
             BufferedImage image = createImage(code);
+            // 将图片写入outputStream,转换为指定格式(IMAGE_FORMAT)
             ImageIO.write(image, IMAGE_FORMAT, outputStream);
 
+            // 将outputStream中的图片数据转换为byte数组
             byte[] data = outputStream.toByteArray();
+            // 将图片数据转换为Base64编码的字符串,返回
             return "data:image/" + IMAGE_FORMAT + ";base64," + Base64.getEncoder().encodeToString(data);
         }
     }
 
-    private static BufferedImage createImage(String verifyCode) throws IOException, FontFormatException {
-        BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
-        Graphics2D graphics = image.createGraphics();
-
-        graphics.setColor(Color.WHITE);
-        graphics.fillRect(0, 0, WIDTH, HEIGHT);
-
-
-        Font font = graphics.getFont();
-        if (font == null) {
-            Resource resource = resourcePatternResolver.getResource("classpath:font/SourceHanSansSC-Regular-2.otf");
-
-            try (
-                    InputStream inputStream = resource.getInputStream()
-            ) {
-                font = Font.createFont(Font.TRUETYPE_FONT, inputStream);
-            }
-        }
-        font = font.deriveFont((float) (HEIGHT - 10));
-        graphics.setFont(font);
-
-        int desX, desY = HEIGHT - 10, distance = 18;
-//        绘制验证码
-        for (int i = 0; i < verifyCode.length(); i++) {
-            graphics.setColor(COLORS[RANDOM.nextInt(COLORS.length)]);
-            desX = i * distance + 18;
-            graphics.drawString(Character.toString(verifyCode.charAt(i)), desX, desY + RANDOM.nextInt(desY % 10));
-        }
-//        绘制干扰线
-        for (int x = 0; x < 6; x++) {
-            graphics.setColor(getRandomColor());
-            graphics.drawLine(RANDOM.nextInt(WIDTH), RANDOM.nextInt(HEIGHT), RANDOM.nextInt(WIDTH), RANDOM.nextInt(HEIGHT));
+/**
+ * 创建一个包含验证码文本的图像。
+ *
+ * @param verifyCode 验证码文本内容。
+ * @return 一个包含验证码的{@link BufferedImage}对象。
+ * @throws IOException 如果读取字体文件或生成图像时发生IO异常。
+ * @throws FontFormatException 如果字体格式不正确。
+ */
+private static BufferedImage createImage(String verifyCode) throws IOException, FontFormatException {
+    // 初始化图像对象
+    BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
+    Graphics2D graphics = image.createGraphics();
+    // 设置背景色并填充背景
+    graphics.setColor(Color.WHITE);
+    graphics.fillRect(0, 0, WIDTH, HEIGHT);
+    // 设置验证码字体
+    Font font = graphics.getFont();
+    if (font == null) {
+        // 从资源文件中加载字体
+        Resource resource = resourcePatternResolver.getResource("classpath:font/SourceHanSansSC-Regular-2.otf");
+        try (
+                InputStream inputStream = resource.getInputStream()
+        ) {
+            font = Font.createFont(Font.TRUETYPE_FONT, inputStream);
         }
+    }
+    // 调整字体大小
+    font = font.deriveFont((float) (HEIGHT - 10));
+    graphics.setFont(font);
+    int desX, desY = HEIGHT - 10, distance = 18;
+
+    // 绘制验证码文本
+    for (int i = 0; i < verifyCode.length(); i++) {
+        // 随机选择颜色
+        graphics.setColor(COLORS[RANDOM.nextInt(COLORS.length)]);
+        desX = i * distance + 18;
+        // 在图像上绘制每个字符
+        graphics.drawString(Character.toString(verifyCode.charAt(i)), desX, desY + RANDOM.nextInt(desY % 10));
+    }
 
-        graphics.dispose();
-        return image;
+    // 绘制干扰线
+    for (int x = 0; x < 6; x++) {
+        // 随机选择颜色
+        graphics.setColor(getRandomColor());
+        // 在图像上随机绘制线条
+        graphics.drawLine(RANDOM.nextInt(WIDTH), RANDOM.nextInt(HEIGHT), RANDOM.nextInt(WIDTH), RANDOM.nextInt(HEIGHT));
     }
+    // 释放Graphics2D资源
+    graphics.dispose();
+    return image;
+}
 
+    /**
+     * 生成一个随机颜色。
+     * 该方法不接受任何参数。
+     *
+     * @return Color 返回一个随机生成的颜色对象,其中红、绿、蓝分量的取值范围为0到255。
+     */
     private static Color getRandomColor() {
+        // 生成红、绿、蓝分量的随机值
         int r = RANDOM.nextInt(256);
         int g = RANDOM.nextInt(256);
         int b = RANDOM.nextInt(256);
+        // 使用随机生成的红、绿、蓝分量创建并返回一个颜色对象
         return new Color(r, g, b);
     }
+
 }

+ 226 - 79
src/main/java/com/scbfkj/uni/library/MapTools.java

@@ -1,78 +1,103 @@
 package com.scbfkj.uni.library;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
-
 import java.io.*;
 import java.math.BigInteger;
 import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
-import java.text.ParseException;
 import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-public class MapTools implements Serializable {
+public class MapTools {
+
+
+
+    /**
+     * 将字符串形式的映射或数组转换为对象。
+     * @param inMapStr 输入的字符串,可以是JSON或类似格式的字符串。
+     * @param itemMapList 用于存储中间计算结果的列表,可以为空。
+     * @param strType 指示字符串类型的数组,长度为0表示处理MAP类型,长度大于0时表示处理数组类型,第二个元素指定分隔符。
+     * @return 根据输入的字符串类型返回相应的对象,如果是MAP类型,则返回最终的Map对象或者如果处理的是数组,则返回包含所有元素的List对象。
+     */
+    private static Object mapStrToObj(String inMapStr, List<Object> itemMapList, String... strType) {
+        // 初始化开始和结束字符,以及中间连接字符
+        String beginChar = strType.length == 0 ? "{" : "[";
+        String endChar = strType.length == 0 ? "}" : "]";
+        String midChar = strType.length < 2 ? "=" : strType[1];
+
+        // 初始化或重置itemMapList
+        itemMapList = (Objects.isNull(itemMapList) || itemMapList.isEmpty()) ? new ArrayList<>() : itemMapList;
 
+        String tempMapStr = inMapStr; // 避免污染原始输入字符串
+        while (true) {
+            // 查找并处理每个独立的MAP或数组
+            int lastLocation = tempMapStr.lastIndexOf(beginChar);
+            int mapEndLocation = tempMapStr.indexOf(endChar, lastLocation);
+            if (lastLocation < 0 || mapEndLocation < 0) break;
 
+            String itemMapStr = tempMapStr.substring(lastLocation, mapEndLocation + 1);
+            String replaceStr = itemMapStr; // 用于后续的替换操作
 
-    private static Object mapStrToObj(String inMapStr, List<Object> itemMapList, String... strType) {//
-        String beginChar = strType.length == 0 ? "{" : "[";//为了递归数组准备
-        String endChar = strType.length == 0 ? "}" : "]"; //}
-        String midChar = strType.length < 2 ? "=" : strType[1];//兼容JSON格式
-        itemMapList = (Objects.isNull(itemMapList) || itemMapList.isEmpty()) ? new ArrayList<>() : itemMapList;//中间计算结果:从入口进入是为了递归数组准备
-        String tempMapStr = inMapStr;//为避免入口参数污染 [A]
-        while (true) {//遍历字符串
-            int lastLocation = tempMapStr.lastIndexOf(beginChar);//查找最后一个{,一定是独立层,无论在哪 《0》
-            int mapEndLocation = tempMapStr.indexOf(endChar, lastLocation);//查找第一个匹配的内容
-            if (lastLocation < 0 || mapEndLocation < 0) break;//找不到代表数据遍历完或数据格式有错误
-            String itemMapStr = tempMapStr.substring(lastLocation, mapEndLocation + 1);//获取一个子MAP,注意不要去掉两头括号,方便进行计算替换[1]
-            String replaceStr = itemMapStr;//为后面替换进行准备,避免数据污染 {A=[a]}
+            // 如果包含数组,则递归处理
             if (itemMapStr.indexOf("[") > 0 && itemMapStr.indexOf("]") > 0) {
                 Map<String, Object> tempObj = (Map<String, Object>) mapStrToObj(itemMapStr, itemMapList, "arr");
                 itemMapStr = tempObj.get("itemMapStr").toString();
                 itemMapList = (List<Object>) tempObj.get("itemMapList");
             }
-            String[] columnList = itemMapStr.replace(beginChar, "").replace(endChar, "").replaceAll("\"", "").split(",", -1);//使用逗号分割 //
+
+            // 解析当前MAP或数组字符串
+            String[] columnList = itemMapStr.replace(beginChar, "").replace(endChar, "").replaceAll("\"", "").split(",", -1);
             Map<String, Object> itemMap = new HashMap<>();
             List<Object> itemList = new ArrayList<>();
-            for (String s : columnList) { //s= [1]
+            for (String s : columnList) {
                 Object columnValue = "";
                 String keyName = null;
-                if (strType.length == 0) { //
-                    //{A="12:00:00"}
+
+                if (strType.length == 0) {
+                    // 处理MAP类型的键值对
                     midChar = !s.contains(":") ? "=" : !s.contains("=") ? ":" : s.indexOf("=") > s.indexOf(":") ? ":" : "=";
-                    String[] colValue = s.split(midChar, -1); // [X1,1]
+                    String[] colValue = s.split(midChar, -1);
+
                     if (s.contains(":") && s.lastIndexOf(":") > s.indexOf(":")) {
-                        keyName = colValue[0].replace("'", "").replace("\"", "").trim(); //X1
+                        keyName = colValue[0].replace("'", "").replace("\"", "").trim();
                         columnValue = s.substring(s.indexOf(":") + 1);
                     } else {
-                        if (colValue.length != 2) continue; //  || Objects.equals(colValue[0], "")
-                        keyName = colValue[0].replace("'", "").replace("\"", "").trim(); //X1
-                        columnValue = Objects.equals(colValue[1], "null") ? null : (colValue[1].trim()); //1 Objects.equals(colValue[1], "") ||
+                        if (colValue.length != 2) continue;
+                        keyName = colValue[0].replace("'", "").replace("\"", "").trim();
+                        columnValue = Objects.equals(colValue[1], "null") ? null : (colValue[1].trim());
                     }
-
                 } else {
+                    // 处理数组类型的元素
                     columnValue = s;
                 }
+
+                // 处理引用其他元素的情况
                 if (columnValue != null && columnValue.toString().startsWith("《") && columnValue.toString().endsWith("》")) {
                     String columnValueIndex = columnValue.toString().replace("《", "").replace("》", "");
                     if (!MapTools.isNumber(columnValueIndex)) continue;
                     columnValue = itemMapList.get(Integer.parseInt(columnValueIndex));
                 }
+
                 if (strType.length == 0) {
-                    itemMap.put(keyName, columnValue); // X1,1
+                    itemMap.put(keyName, columnValue);
                 } else {
                     itemList.add(columnValue);
                 }
             }
-            tempMapStr = tempMapStr.replace(replaceStr, "《" + itemMapList.size() + "》");//用于父级获取对应的值   《0》
-            itemMapList.add(strType.length == 0 ? itemMap : itemList); //[{X1:1}]
+
+            // 替换原始字符串中的当前MAP或数组部分,以便在父级中引用
+            tempMapStr = tempMapStr.replace(replaceStr, "《" + itemMapList.size() + "》");
+            itemMapList.add(strType.length == 0 ? itemMap : itemList);
         }
-        if (tempMapStr.contains("[") && tempMapStr.contains("]")) {  // 《0》
+
+        // 处理剩余的数组部分
+        if (tempMapStr.contains("[") && tempMapStr.contains("]")) {
             Object tempMapData = mapStrToObj(" " + tempMapStr + " ", itemMapList, "arr", midChar);
             tempMapStr = tempMapData.toString();
         }
+
+        // 将引用转换为实际的对象
         Map<Object, Object> temMap = new HashMap<>();
         temMap.put("itemMapStr", tempMapStr);
         temMap.put("itemMapList", itemMapList);
@@ -92,139 +117,208 @@ public class MapTools implements Serializable {
                             continue;
                         }
                     }
-
                     temp.put(key, value);
-
                 }
                 itemMapList.set(i, temp);
             } else {
                 System.out.println("1111");
             }
         }
+
+        // 清理对象,可能用于处理循环引用或无用对象
         itemMapList = cleanObject(itemMapList);
+
+        // 根据输入类型返回相应的结果
         return strType.length == 0 ? (itemMapList.size() == 0 ? itemMapList : itemMapList.get(itemMapList.size() - 1)) : temMap;
     }
 
 
-    private static <T> T cleanObject(T obj) {
-        if (obj instanceof Map<?, ?>) {
-            Map<String, ?> map = (Map<String, ?>) obj;
-            return (T) cleanMap(map);
-        } else if (obj instanceof Collection<?> collection) {
-            return (T) collection.stream().map(MapTools::cleanObject).toList();
-        } else if (obj instanceof String str) {
-            return (T) str.replaceAll("^\\\\+", "").replaceAll("\\\\+$", "");
-        } else {
-            return obj;
+    /**
+     * 清洗对象。该方法旨在对给定的对象进行清洗,具体的清洗逻辑如下:
+     * 1. 如果对象是Map类型,则调用cleanMap方法进行清洗,并返回清洗后的Map对象。
+     * 2. 如果对象是Collection类型,则对集合中的每个元素调用cleanObject方法进行清洗,并返回清洗后的List对象。
+     * 3. 如果对象是String类型,则移除字符串两端的反斜杠,并返回清洗后的String对象。
+     * 4. 如果对象不是上述任意一种类型,则直接返回原对象。
+     *
+     * @param obj 需要清洗的对象,可以是任意类型。
+     * @return 清洗后的对象,类型与输入对象相同。
+     * @param <T> 输入和输出对象的类型。
+     */
+        private static <T> T cleanObject(T obj) {
+            if (obj instanceof Map<?, ?>) {
+                // 如果对象是Map类型,进行特殊处理
+                Map<String, ?> map = (Map<String, ?>) obj;
+                return (T) cleanMap(map);
+            } else if (obj instanceof Collection<?> collection) {
+                // 如果对象是Collection类型,对每个元素进行清洗
+                return (T) collection.stream().map(MapTools::cleanObject).toList();
+            } else if (obj instanceof String str) {
+                // 如果对象是String类型,移除两端的反斜杠
+                return (T) str.replaceAll("^\\\\+", "").replaceAll("\\\\+$", "");
+            } else {
+                // 对于其他类型,直接返回原对象
+                return obj;
+            }
         }
-    }
 
+    /**
+     * 清洗给定的Map,对键进行处理并递归清洗值对象。
+     *
+     * @param map 需要清洗的Map,其中键为String类型,值为泛型V。
+     * @return 清洗后的Map,其中键经过处理(移除前后出现的反斜杠),值经过递归清洗。
+     */
     private static <V> Map<String, V> cleanMap(Map<String, V> map) {
+        // 创建一个新的HashMap用于存放清洗后的结果
         Map<String, V> result = new HashMap<>();
+        // 遍历原Map的entry集合,对每个键值对进行处理
         for (Map.Entry<String, V> stringObjectEntry : map.entrySet()) {
+            // 处理键,移除键两端的反斜杠
             String key = stringObjectEntry.getKey().toString().replaceAll("^\\\\+", "").replaceAll("\\\\+$", "");
+            // 获取值,并递归进行清洗
             V value = stringObjectEntry.getValue();
 
+            // 将清洗后的键值对存入结果Map中
             result.put(key, cleanObject(value));
         }
+        // 返回清洗后的Map
         return result;
     }
 
 
     /**
-     * java正则提取多个结果
+     * 使用Java正则表达式提取字符串中的多个匹配结果。
      *
-     * @param str     字符串
-     * @param pattern 正则表达式
-     * @return 匹配的结果集
+     * @param str         需要进行匹配的原始字符串
+     * @param pattern     用于匹配的正则表达式
+     * @return            匹配的结果集合,以List<String>形式返回。
      */
     public static List<String> patternContent(String str, String pattern) {
-        // 编写正则表达式
-        // 匹配当前正则表达式
+        // 编译正则表达式并创建匹配器
         Matcher matcher = Pattern.compile(pattern).matcher(str);
-        // 定义当前文件的文件名称
+        // 存储匹配结果的列表
         List<String> arrayList = new ArrayList<>();
-        // 判断是否可以找到匹配正则表达式的字符
+
+        // 循环查找下一个匹配项,并将匹配项添加到列表中
         while (matcher.find()) {
-            // 将匹配当前正则表达式的字符串即文件名称进行赋值
             arrayList.add(matcher.group());
         }
-        // 返回
+
+        // 返回所有匹配结果
         return arrayList;
     }
 
 
+
+    /**
+     * 根据指定的正则表达式在字符串中寻找匹配项。
+     *
+     * @param str 需要进行匹配搜索的原始字符串。
+     * @param pattern 用于匹配的正则表达式。
+     * @return 找到的第一个匹配项,如果没有匹配项则返回null。
+     */
     public static String patternKey(String str, String pattern) {
-        // 编写正则表达式
-        // 匹配当前正则表达式
+        // 编译正则表达式并创建匹配器
         Matcher matcher = Pattern.compile(pattern).matcher(str);
-        // 定义当前文件的文件名称
-        // 判断是否可以找到匹配正则表达式的字符
+        // 遍历字符串,寻找第一个匹配项
         while (matcher.find()) {
-            // 将匹配当前正则表达式的字符串即文件名称进行赋值
+            // 返回找到的匹配项
             return matcher.group();
         }
-        // 返回
+        // 如果没有找到匹配项,则返回null
         return null;
     }
 
     /**
-     * 获得字符串的值,如果是空字符串则为null
+     * 获得字符串的值,检查字符串是否为空白。如果字符串是空白的,则返回null,否则返回原字符串。
+     * 这个方法主要用于处理XML标签中可能存在的空字符串值,将其标准化为null。
      *
-     * @return xml标签值为空字符串:替换成null
+     * @param str 待检查的字符串。
+     * @return 如果输入的字符串是空白的,则返回null;如果字符串非空非空白,则返回原字符串。
      */
     public static String getText(String str) {
+        // 判断字符串是否为空白,如果是则返回null,否则返回原字符串
         return MapTools.isBlank(str) ? null : str;
     }
 
     /**
-     * list 深拷贝
+     * 实现List的深拷贝。
+     * 通过序列化和反序列化的方式,创建源List的一个新的副本。
+     * 这种方式可以拷贝List中所有的元素,包括嵌套的List或其他可序列化的对象。
+     * 注意:此方法仅适用于List中的元素是可序列化的。
      *
-     * @param src 源list
-     * @param <T> list中数据类型
-     * @return 返回拷贝后新list的值
+     * @param src 源List,需要进行深拷贝的列表。
+     * @param <T> List中元素的类型。
+     * @return 返回一个新的List,它是源List的深拷贝。如果拷贝过程中发生异常,则返回null。
      */
     public static <T> List<T> deepCopy(List<T> src) {
         try {
+            // 序列化源List到字节数组
             ByteArrayOutputStream byteout = new ByteArrayOutputStream();
             ObjectOutputStream out = new ObjectOutputStream(byteout);
             out.writeObject(src);
+
+            // 从字节数组反序列化回List对象
             ByteArrayInputStream bytein = new ByteArrayInputStream(byteout.toByteArray());
             ObjectInputStream in = new ObjectInputStream(bytein);
             @SuppressWarnings("unchecked") List<T> dest = (List<T>) in.readObject();
+
+            // 关闭流
             in.close();
+
+            // 返回深拷贝后的List
             return dest;
         } catch (ClassNotFoundException | IOException e) {
+            // 如果发生异常,返回null
             return null;
         }
     }
 
+
+    /**
+     * 克隆Map对象的静态方法。
+     * 通过序列化和反序列化的方式实现深拷贝。
+     *
+     * @param obj 要进行克隆的原始Map对象,键为String类型,值为Object类型。
+     * @return HashMap 类型的克隆对象,如果克隆失败则返回null。
+     * @param <HashMap> 继承自Serializable的HashMap类型。
+     */
     public static <HashMap extends Serializable> HashMap clone(Map<String, Object> obj) {
         HashMap clonedObj = null;
         try {
+            // 将原始对象序列化到字节数组输出流中
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(baos);
             oos.writeObject(obj);
+
+            // 将序列化的字节数组反序列化为对象输入流
             ByteArrayInputStream bytein = new ByteArrayInputStream(baos.toByteArray());
             ObjectInputStream ois = new ObjectInputStream(bytein);
+
+            // 从对象输入流中读取克隆对象
             clonedObj = (HashMap) ois.readObject();
+
+            // 关闭对象输入流
             ois.close();
         } catch (Exception e) {
+            // 如果过程中发生异常,则返回null
             return null;
         }
         return clonedObj;
     }
 
     /**
-     * 从map中获取returnData获取List
+     * 从传入的map中获取键为"returnData"的值,并将其转换为List<Map<String, Object>>类型返回。
+     * 如果"returnData"不存在或其值不是List类型,则返回null。
      *
-     * @param params
-     * @return
+     * @param params 包含待查询键"returnData"的Map对象
+     * @return 如果"returnData"键存在且值为List类型,则返回该List;否则返回null。
      */
-
     public static List<Map<String, Object>> getMapList(Map<String, Object> params) {
+        // 检查"returnData"是否存在,若不存在则直接返回null
         if (Objects.isNull(params.get("returnData"))) return null;
+
         Object returnData = params.get("returnData");
+        // 判断"returnData"的值是否为List类型,是则转换类型并返回,否则返回null
         if (returnData instanceof List) {
             return (List<Map<String, Object>>) returnData;
         } else {
@@ -233,66 +327,119 @@ public class MapTools implements Serializable {
     }
 
 
-    /*字符串空判断*/
+
+    /**
+     * 判断字符串是否为空或仅包含空格、制表符、换行符等空白字符。
+     *
+     * @param s 待检查的字符串。
+     * @return 如果字符串为null、空字符串(""),或者只包含空白字符,则返回true;否则返回false。
+     */
     public static boolean isBlank(final String s) {
+        // 首先检查字符串是否为null或空
         if (s == null || s.isEmpty()) {
             return true;
         }
+        // 遍历字符串中的每个字符,检查是否有非空白字符
         for (int i = 0; i < s.length(); i++) {
             char c = s.charAt(i);
+            // 如果发现非空白字符,则返回false
             if (!Character.isWhitespace(c)) {
                 return false;
             }
         }
+        // 字符串中所有字符都是空白字符,返回true
         return true;
     }
 
-    /*字符串非空判断*/
+
+    /**
+     * 判断字符串是否非空。
+     * 该方法通过调用isBlank(s)来判断字符串是否为空或仅包含空格字符。
+     * 如果字符串非空或仅包含空格字符,则返回false;如果字符串为null或为空,则返回true。
+     *
+     * @param s 待判断的字符串
+     * @return 如果字符串非空,则返回true;否则返回false。
+     */
     public static boolean isNotBlank(final String s) {
         return !isBlank(s);
     }
 
 
+
     /**
      * 判断字符串是否是数字
      *
-     * @param str 字符串
-     * @return 是数字:true ,否则false
+     * @param str 需要判断的字符串
+     * @return 返回布尔值,如果字符串是数字则返回true,否则返回false。
      */
     public static boolean isNumber(String str) {
+        // 尝试将字符串解析为双精度浮点数
         try {
             Double.parseDouble(str);
-            return true;
+            return true; // 可以解析,说明是数字,返回true
         } catch (Exception e) {
-            return false;
+            return false; // 解析失败,说明不是数字,返回false
         }
     }
 
+
+    /**
+     * 处理成功响应的函数。
+     *
+     * @param returnData 返回的数据对象,可以是任意类型,这个数据会直接放入返回的Map中。
+     * @return 返回一个Map<String, Object>,其中包含处理结果的代码(固定为"0"表示成功)和返回的数据对象。
+     */
     public static Map<String, Object> processSuccess(Object returnData) {
-        Map<String, Object> returnMap = new HashMap<>();//用于当前方法统一返回参数,不存在深拷贝问题
+        // 初始化返回的Map,用于存放处理结果和数据
+        Map<String, Object> returnMap = new HashMap<>();
+
+        // 设置返回码为"0",表示成功
         returnMap.put("code", "0");
+        // 将传入的数据对象放入Map中
         returnMap.put("returnData", returnData);
+
         return returnMap;
     }
 
-    //统一错误信息处理
+    /**
+     * 统一错误信息处理函数。
+     * 用于在发生错误时,生成一个包含错误代码和错误信息的Map对象,方便统一返回给调用方。
+     *
+     * @param errorMessage 错误信息,描述具体的错误内容。
+     * @return 返回一个Map对象,包含错误代码和错误信息。
+     */
     public static Map<String, Object> processFail(String errorMessage) {
-        Map<String, Object> returnMap = new HashMap<>();//用于当前方法统一返回参数,不存在深拷贝问题
+        // 初始化返回参数Map,用于存放错误代码和错误信息
+        Map<String, Object> returnMap = new HashMap<>();
+
+        // 设置错误代码为"-1",表示发生错误
         returnMap.put("code", "-1");
+        // 设置错误信息为传入的errorMessage
         returnMap.put("message", errorMessage);
+
         return returnMap;
     }
 
 
+    /**
+     * 获取输入字符串的MD5加密结果
+     *
+     * @param str 需要进行MD5加密的原始字符串
+     * @return 经过MD5加密后,转换为16进制字符串的结果。如果加密过程出错,则返回null。
+     */
     public static String getMD5Str(String str) {
         try {
+            // 获取MD5算法实例
             MessageDigest md5 = MessageDigest.getInstance("md5");
+            // 对输入字符串进行MD5加密处理
             byte[] digest = md5.digest(str.getBytes(StandardCharsets.UTF_8));
+            // 将加密结果转换为16进制字符串
             return new BigInteger(1, digest).toString(16);
         } catch (NoSuchAlgorithmException e) {
+            // 处理加密算法找不到的异常
             e.printStackTrace();
         }
-        //16是表示转换为16进制数
+        // 由于异常处理,理论上不会执行到这里,这里返回null只是作为异常情况的备份
         return null;
     }
 }

+ 220 - 91
src/main/java/com/scbfkj/uni/library/RequestUtil.java

@@ -16,171 +16,300 @@ public class RequestUtil {
     private RequestUtil() {
     }
 
+    /**
+     * 获取客户端IP地址
+     * 该方法首先尝试从HTTP请求头中的"x-forwarded-for"字段获取IP地址,如果该字段不存在或为空,
+     * 则尝试从"Proxy-Client-IP"字段获取,接着是"WL-Proxy-Client-IP"字段,
+     * 如果所有尝试都失败或返回不可识别的值,则返回远程地址。
+     * 注意:这个方法适用于通过代理或负载均衡服务器转发的请求获取真实客户端IP地址的场景。
+     *
+     * @return 客户端的IP地址字符串。如果无法确定客户端IP地址,则返回null。
+     */
     public static String getIpAddr() {
-        String ip = getHeader("x-forwarded-for");
+        String ip = getHeader("x-forwarded-for"); // 尝试从"x-forwarded-for"头部获取IP地址
         String unknown = "unknown";
         if (ip == null || ip.isEmpty() || unknown.equalsIgnoreCase(ip)) {
-            ip = getHeader("Proxy-Client-IP");
+            ip = getHeader("Proxy-Client-IP"); // 如果失败,尝试从"Proxy-Client-IP"头部获取
         }
         if (ip == null || ip.isEmpty() || unknown.equalsIgnoreCase(ip)) {
-            ip = getHeader("WL-Proxy-Client-IP");
+            ip = getHeader("WL-Proxy-Client-IP"); // 如果再次失败,尝试从"WL-Proxy-Client-IP"头部获取
         }
         if (ip == null || ip.isEmpty() || unknown.equalsIgnoreCase(ip)) {
-            ip = getRemoteAddr();
+            ip = getRemoteAddr(); // 所有尝试失败,返回远程地址
         }
         return ip;
     }
 
+    /**
+     * 获取当前请求的客户端IP地址。
+     *
+     * 该方法不接受任何参数,它通过检索当前线程绑定的ServletRequestAttributes,
+     * 进而获取HttpServletRequest对象,最后从HttpServletRequest中提取客户端的IP地址。
+     *
+     * @return String 客户端的IP地址。
+     */
     private static String getRemoteAddr() {
+        // 获取当前请求的属性
         ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
+        // 从属性中获取HttpServletRequest对象
         HttpServletRequest request = requestAttributes.getRequest();
+        // 返回客户端的IP地址
         return request.getRemoteAddr();
     }
 
-    public static String getAppToken() {
-//        请求
-        Object appToken = getHeader("token");
-        return Objects.nonNull(appToken) ? appToken.toString() : null;
+/**
+ * 获取应用令牌。
+ * <p>此方法从请求头中获取名为"token"的字段值,并返回其字符串表示形式。
+ * 如果找不到该字段或字段值为null,则返回null。</p>
+ *
+ * @return 如果找到有效的token,则返回其字符串形式;否则返回null。
+ */
+public static String getAppToken() {
+    // 从请求头中获取名为"token"的字段值
+    Object appToken = getHeader("token");
+    // 判断appToken是否非空,非空则返回其字符串形式,否则返回null
+    return Objects.nonNull(appToken) ? appToken.toString() : null;
+}
 
-    }
 
+    /**
+     * 获取用户令牌。
+     * <p>
+     * 该方法从请求头中提取名为"usertoken"的字段,并返回其值。
+     * 如果不存在该字段,则返回null。
+     *
+     * @return 用户令牌的字符串表示,如果不存在则返回null。
+     */
     public static String getUserToken() {
+        // 从请求头中获取名为"usertoken"的字段
         Object userToken = getHeader("usertoken");
+        // 判断用户令牌是否非空,非空则返回其字符串形式,否则返回null
         return Objects.nonNull(userToken) ? userToken.toString() : null;
     }
 
+    /**
+     * 获取当前HTTP请求的指定头信息。
+     *
+     * @param headerName 需要获取的头名称。
+     * @return 返回请求头中指定头名称的值。如果不存在该头,则返回null。
+     */
     private static String getHeader(String headerName) {
+        // 获取当前请求的属性
         ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
+        // 从属性中获取HttpServletRequest对象
         HttpServletRequest request = requestAttributes.getRequest();
+        // 返回指定头名称的值
         return request.getHeader(headerName);
     }
+    /**
+     * 获取当前HTTP请求的所有头信息。
+     *
+     * 该方法不接受任何参数,但需要当前线程绑定的HTTP请求上下文。
+     *
+     * @return 一个包含所有头信息的Map,其中头名称为键,头值为值。
+     */
     public static Map<String, String> getHeaders() {
+        // 获取当前请求的属性
         ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
+        // 从属性中获取HttpServletRequest对象
         HttpServletRequest request = requestAttributes.getRequest();
+        // 获取所有头名称的枚举
         Enumeration<String> headerNames = request.getHeaderNames();
+        // 创建一个空的Map来存储头信息
         Map<String,String> headers = new HashMap<>();
+        // 遍历所有头名称,并将它们及其对应的值添加到Map中
         while (headerNames.hasMoreElements()) {
             String element = headerNames.nextElement();
             headers.put(element,request.getHeader(element));
         }
+        // 返回包含所有头信息的Map
         return headers;
     }
 
-    public static String getAppId() throws Exception {
-        String session = getSessionId();
-        if (session == null) {
-            return null;
-        }
-//        请求
-        Map<String, Object> sessionMap = Config.cache.get(session);
-        if (sessionMap == null) {
-            sessionMap = new Hashtable<>();
-            Config.cache.put(session, sessionMap);
-        }
-        Object appid = sessionMap.get(APP_ID);
-        if (Objects.nonNull(appid)) {
-            return appid.toString();
-        }
-        return getApplication().get(APP_ID).toString();
-
+/**
+ * 获取应用程序ID。
+ * 此方法首先尝试从会话ID中检索应用程序ID。如果会话ID不存在或相关应用程序ID未找到,
+ * 则方法将尝试从应用程序实例中获取应用程序ID。
+ *
+ * @return 返回应用程序ID的字符串表示。如果无法获取有效的应用程序ID,则返回null。
+ * @throws Exception 如果在获取会话ID或应用程序ID过程中遇到错误,则抛出异常。
+ */
+public static String getAppId() throws Exception {
+    String session = getSessionId(); // 尝试获取会话ID
+    if (session == null) {
+        return null; // 如果会话ID不存在,直接返回null
+    }
+    // 尝试从缓存中获取会话信息
+    Map<String, Object> sessionMap = Config.CACHE.get(session);
+    if (sessionMap == null) {
+        sessionMap = new Hashtable<>(); // 如果会话信息不存在,则创建新的会话信息容器
+        Config.CACHE.put(session, sessionMap); // 将新的会话信息容器放入缓存
     }
+    // 尝试从会话信息中获取应用程序ID
+    Object appid = sessionMap.get(APP_ID);
+    if (Objects.nonNull(appid)) {
+        return appid.toString(); // 如果找到应用程序ID,返回其字符串形式
+    }
+    // 如果在会话信息中未找到应用程序ID,尝试从应用程序实例中获取并返回
+    return getApplication().get(APP_ID).toString();
+}
 
-    public static Map<String, Object> getApplication() throws Exception {
 
-        String session = getSessionId();
-        String clean = "delete from appconnectlog where expiretime <  ?";
+/**
+ * 获取当前应用的信息。
+ * <p>
+ * 这个方法首先会尝试从会话中获取应用信息。如果会话中不存在该信息,则会通过应用令牌和请求IP来查询数据库,
+ * 获取应用的详细信息,并将其保存到会话中,供后续使用。
+ * </p>
+ * @return 一个包含应用信息的Map对象。如果会话不存在或应用未登录,则返回null。
+ * @throws Exception 如果查询数据库时发生错误,或者无法获取应用信息,则抛出异常。
+ */
+public static Map<String, Object> getApplication() throws Exception {
 
-//        清理过期数据
-        DATABASE.update(Config.getSecurityConnectionStr(), clean, LocalDateTime.now());
-//        请求
-        if (session == null) {
-            return null;
-        }
-        Map<String, Object> sessionMap = Config.cache.get(session);
-        if (sessionMap == null) {
-            sessionMap = new Hashtable<>();
-            Config.cache.put(session, sessionMap);
-        }
-        Object application = sessionMap.get("application");
-        if (Objects.isNull(application)) {
-            String appToken = getAppToken();
-            String requestIp = getIpAddr();
-            String query = "select appid from appconnectlog where apptoken=? and requestip =? and expiretime >  ?";
-            List<Map<String, Object>> appConnectLogList = DATABASE.query(Config.getSecurityConnectionStr(), query,
-                    appToken, requestIp, LocalDateTime.now());
-            if (appConnectLogList.isEmpty()) {
-                throw new RuntimeException("当前连接未登录");
-            }
-            Map<String, Object> stringObjectMap = appConnectLogList.get(0);
-            Object applicationid = stringObjectMap.get(APP_ID);
-
-            query = """
-                    select applicationid,
-                           appid,
-                           appsecret,
-                           appname,
-                           appengname,
-                           appdescribe,
-                           applogo,
-                           smalllogo,
-                           backgroundimage,
-                           apptokeneffective,
-                           securitycoderule,
-                           securitycodeeffective,
-                           multilogin,
-                           passwordrule,
-                           passwordeffective
-                    from application
-                    where appid = ?""";
-            List<Map<String, Object>> applicationList = DATABASE.query(Config.getSecurityConnectionStr(), query, applicationid);
-            if (applicationList.isEmpty()) {
-                throw new RuntimeException("获取应用失败");
-            }
-            application = applicationList.get(0);
-
-            sessionMap.put("application", application);
+    String session = getSessionId();
+    String clean = "delete from appconnectlog where expiretime <  ?";
 
+    // 清理数据库中过期的连接日志
+    DATABASE.update(Config.getSecurityConnectionStr(), clean, LocalDateTime.now());
+
+    // 检查会话是否有效
+    if (session == null) {
+        return null;
+    }
+    Map<String, Object> sessionMap = Config.CACHE.get(session);
+    if (sessionMap == null) {
+        sessionMap = new Hashtable<>();
+        Config.CACHE.put(session, sessionMap);
+    }
+    // 尝试从会话映射中获取应用信息
+    Object application = sessionMap.get("application");
+    if (Objects.isNull(application)) {
+        // 如果应用信息不存在,则通过应用令牌和IP地址查询应用连接日志
+        String appToken = getAppToken();
+        String requestIp = getIpAddr();
+        String query = "select appid from appconnectlog where apptoken=? and requestip =? and expiretime >  ?";
+        List<Map<String, Object>> appConnectLogList = DATABASE.query(Config.getSecurityConnectionStr(), query,
+                appToken, requestIp, LocalDateTime.now());
+        // 如果查询结果为空,表示应用未登录
+        if (appConnectLogList.isEmpty()) {
+            throw new RuntimeException("当前连接未登录");
         }
-        Map<String, Object> applicationMap = (Map<String, Object>) application;
+        // 获取应用ID
+        Map<String, Object> stringObjectMap = appConnectLogList.get(0);
+        Object applicationid = stringObjectMap.get(APP_ID);
 
-        return applicationMap;
+        // 根据应用ID查询应用的详细信息
+        query = """
+                select applicationid,
+                       appid,
+                       appsecret,
+                       appname,
+                       appengname,
+                       appdescribe,
+                       applogo,
+                       smalllogo,
+                       backgroundimage,
+                       apptokeneffective,
+                       securitycoderule,
+                       securitycodeeffective,
+                       multilogin,
+                       passwordrule,
+                       passwordeffective
+                from application
+                where appid = ?""";
+        List<Map<String, Object>> applicationList = DATABASE.query(Config.getSecurityConnectionStr(), query, applicationid);
+        // 如果查询结果为空,表示无法获取应用信息
+        if (applicationList.isEmpty()) {
+            throw new RuntimeException("获取应用失败");
+        }
+        // 保存查询到的应用信息到会话映射中
+        application = applicationList.get(0);
 
+        sessionMap.put("application", application);
 
     }
+    // 将应用信息转换为Map对象并返回
+    Map<String, Object> applicationMap = (Map<String, Object>) application;
 
-    public static String getUserId() {
+    return applicationMap;
 
-//        请求
-        Map<String, Object> userInfo = getUserInfo();
-        if (Objects.isNull(userInfo)) {
-            return null;
-        } else {
-            Object userid = userInfo.get("userid");
-            return Objects.isNull(userid) ? null : DataFormatUtil.toString(userid);
-        }
+
+}
+
+
+/**
+ * 获取用户ID。
+ * <p>此方法不接受任何参数,尝试从外部获取用户信息,并提取其中的用户ID。</p>
+ *
+ * @return 返回用户ID的字符串形式。如果无法获取用户信息或用户信息中不包含用户ID,则返回null。
+ */
+public static String getUserId() {
+
+    // 尝试获取用户信息
+    Map<String, Object> userInfo = getUserInfo();
+    if (Objects.isNull(userInfo)) {
+        return null;
+    } else {
+        // 从用户信息中提取用户ID,并转换为字符串格式
+        Object userid = userInfo.get("userid");
+        return Objects.isNull(userid) ? null : DataFormatUtil.toString(userid);
     }
+}
 
+
+    /**
+     * 获取用户信息。
+     * 此方法会首先尝试从会话ID中获取用户信息,如果不存在,则返回null。
+     * 如果会话ID存在但对应用户信息为空,则创建一个新的用户信息容器并返回。
+     *
+     * @return Map<String, Object> 如果用户信息存在,则返回一个包含用户信息的Map;否则返回null。
+     */
     public static Map<String, Object> getUserInfo() {
 
+        // 获取当前会话ID
         String session = getSessionId();
+        // 如果会话ID为空,则直接返回null
         if (session == null) {
             return null;
         }
-        Map<String, Object> sessionMap = Config.cache.get(session);
+        // 尝试从缓存中获取会话对应的用户信息
+        Map<String, Object> sessionMap = Config.CACHE.get(session);
+        // 如果该会话ID未被缓存,创建一个新的会话信息容器并加入缓存
         if (sessionMap == null) {
             sessionMap = new Hashtable<>();
-            Config.cache.put(session, sessionMap);
+            Config.CACHE.put(session, sessionMap);
         }
+        // 尝试从会话信息容器中获取用户信息
         Object userInfo = sessionMap.get("userinfo");
+        // 如果用户信息存在,则返回,否则返回null
         return Objects.nonNull(userInfo) ? (Map<String, Object>) userInfo : null;
     }
 
+    /**
+     * 获取会话ID。
+     *
+     * 该方法是一个静态方法,不需要实例化对象即可调用。它通过调用另一个名为getHeader的方法,
+     * 并传入参数"sessionid"来获取会话ID。会话ID通常用于追踪和识别用户在应用程序中的会话。
+     *
+     * @return 返回一个String类型的会话ID。如果无法获取到会话ID,则可能返回null或空字符串,
+     *         具体取决于getHeader方法的实现。
+     */
     public static String getSessionId() {
         return getHeader("sessionid");
     }
 
+    /**
+     * 获取当前请求的URI。
+     *
+     * 该方法不接受任何参数。
+     *
+     * @return 返回当前HTTP请求的URI字符串。
+     */
     public static String getUri() {
+        // 获取当前请求的属性
         ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
+
+        // 从请求属性中提取并返回请求的URI
         return requestAttributes.getRequest().getRequestURI();
     }
 }

+ 49 - 20
src/main/java/com/scbfkj/uni/library/RsaUtils.java

@@ -28,87 +28,116 @@ public final class RsaUtils {
     }
 
     /**
-     * 获取公钥和私钥对,key为公钥,value为私钥
+     * 生成RSA公钥和私钥对,并将其以Map形式返回,其中key为公钥,value为私钥。
      *
-     * @return
-     * @throws NoSuchAlgorithmException
+     * @return 包含公钥和私钥的Map<String, String>。公钥和私钥以Base64编码的字符串形式存储。
+     * @throws NoSuchAlgorithmException 如果指定的算法(此处为RSA)不可用,则抛出此异常。
      */
     public static Map<String, String> genKeyPair() throws NoSuchAlgorithmException {
+        // 实例化RSA的KeyPairGenerator对象
         KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
+        // 使用1024位密钥长度初始化,并通过SecureRandom生成随机数
         keyPairGen.initialize(1024, new SecureRandom());
+        // 生成公钥和私钥对
         KeyPair keyPair = keyPairGen.generateKeyPair();
+        // 将生成的密钥对分别转换为RSAPrivateKey和RSAPublicKey类型
         RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
         RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
+
+        // 将公钥和私钥编码为字符串
         String publicKeyString = null;
         String privateKeyString = null;
 
         publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()), StandardCharsets.UTF_8);
         privateKeyString = new String(Base64.encodeBase64(privateKey.getEncoded()), StandardCharsets.UTF_8);
 
+        // 将公钥和私钥字符串存储在Map中,以"publicKey"和"privateKey"为键
         Map<String, String> keyPairMap = new HashMap<>();
         keyPairMap.put("publicKey", publicKeyString);
         keyPairMap.put("privateKey", privateKeyString);
         return keyPairMap;
     }
 
+
+    /**
+     * 使用RSA算法对字符串进行加密。
+     *
+     * @param str 需要加密的字符串。
+     * @param publicKey 公钥,用于加密过程。
+     * @return 加密后的字符串。
+     * @throws Exception 如果加密过程中出现错误,则抛出异常。
+     */
     public static String encrypt(String str, String publicKey) throws Exception {
+        // 解码公钥
         byte[] decoded = Base64.decodeBase64(publicKey);
+        // 通过解码后的公钥创建RSA公钥对象
         RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA")
                 .generatePublic(new X509EncodedKeySpec(decoded));
+        // 初始化加密器,使用RSA算法和ECB模式
         Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
         cipher.init(1, pubKey);
-        // 分段加密
-        // URLEncoder编码解决中文乱码问题
+
+        // 对字符串进行分段加密,并将结果进行Base64编码
+        // 首先将字符串转换为字节数组,解决中文乱码问题
         byte[] data = URLEncoder.encode(str, StandardCharsets.UTF_8).getBytes(StandardCharsets.UTF_8);
-        // 加密时超过117字节就报错。为此采用分段加密的办法来加密
-        byte[] enBytes = null;
+
+        // 分段加密的过程
+        byte[] enBytes = null; // 用于存储加密后的字节数组
         for (int i = 0; i < data.length; i += MAX_ENCRYPT_BLOCK) {
-            // 注意要使用2的倍数,否则会出现加密后的内容再解密时为乱码
+            // 对每段数据进行加密
             byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i, i + MAX_ENCRYPT_BLOCK));
+            // 将加密后的数据片段合并
             enBytes = ArrayUtils.addAll(enBytes, doFinal);
         }
+        // 将加密后的字节数组进行Base64编码,转换为字符串形式返回
         String outStr = Base64.encodeBase64String(enBytes);
         return outStr;
     }
 
     /**
-     * 公钥分段解密
+     * 使用RSA算法,通过公钥对给定的字符串进行分段解密
      *
-     * @param str
-     * @param privateKey
-     * @return
-     * @throws Exception
+     * @param str 需要解密的字符串。该字符串是使用RSA加密,并经过Base64编码的。
+     * @param privateKey 私钥,用于解密数据。私钥是经过Base64编码的PKCS8格式。
+     * @return 解密后的字符串。解密过程中使用了UTF-8编码。
+     * @throws Exception 如果解密过程中遇到任何错误,则抛出异常。
      */
     public static String decrypt(String str, String privateKey) throws Exception {
-        // 获取公钥
-
+        // 从PKCS8格式的私钥字符串中加载私钥
         PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(java.util.Base64.getDecoder().decode(privateKey.getBytes()));
         RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA")
                 .generatePrivate(pkcs8EncodedKeySpec);
+
+        // 初始化RSA解密器
         Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
-        cipher.init(2, priKey);
+        cipher.init(2, priKey); // 初始化为解密模式
+
+        // 对Base64编码的加密字符串进行解码
         byte[] data = Base64.decodeBase64(str.getBytes(StandardCharsets.UTF_8));
 
-        // 返回UTF-8编码的解密信息
+        // 分段解密数据
         int inputLen = data.length;
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         int offSet = 0;
         byte[] cache;
         int i = 0;
-        // 对数据分段解密
         while (inputLen - offSet > 0) {
+            // 根据RSA加密块的大小分段解密
             if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                 cache = cipher.doFinal(data, offSet, MAX_DECRYPT_BLOCK);
             } else {
                 cache = cipher.doFinal(data, offSet, inputLen - offSet);
             }
-            out.write(cache, 0, cache.length);
+            out.write(cache, 0, cache.length); // 将解密的片段写入输出流
             i++;
-            offSet = i * 128;
+            offSet = i * 128; // 更新偏移量以处理下一段数据
         }
         out.close();
+
+        // 将解密后的字节流转换为字符串,先进行URL解码,再转换为UTF-8编码的字符串
         return URLDecoder.decode(out.toString(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
     }
 
+
 }
 

+ 67 - 1
src/main/java/com/scbfkj/uni/library/UniReturnUtil.java

@@ -6,11 +6,22 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
 import java.util.stream.Collectors;
-
+/**
+ * 提供统一返回格式工具类。
+ */
 public class UniReturnUtil {
+    /**
+     * 私有构造方法,防止实例化。
+     */
     private UniReturnUtil() {
     }
 
+    /**
+     * 构建一个成功返回的数据Map。
+     *
+     * @param data 返回的数据对象。
+     * @return 包含成功标识和返回数据的Map。
+     */
     public static Map<String, Object> success(Object data) {
         HashMap<String, Object> result = new HashMap<>();
         result.put("code", "0");
@@ -19,6 +30,13 @@ public class UniReturnUtil {
         return result;
     }
 
+    /**
+     * 构建一个成功返回的数据Map,允许额外添加其他信息。
+     *
+     * @param data     返回的数据对象。
+     * @param other    包含额外信息的Map。
+     * @return 包含成功标识、返回数据和额外信息的Map。
+     */
     public static Map<String, Object> success(Object data, Map<String, Object> other) {
         Map<String, Object> result = success(data);
         if (Objects.nonNull(other)) {
@@ -27,6 +45,13 @@ public class UniReturnUtil {
         return result;
     }
 
+    /**
+     * 构建一个失败返回的数据Map,允许额外添加其他信息。
+     *
+     * @param message  失败的详细信息。
+     * @param other    包含额外信息的Map。
+     * @return 包含失败标识、错误信息和额外信息的Map。
+     */
     public static Map<String, Object> fail(String message, Map<String, Object> other) {
         Map<String, Object> result = fail(message);
         if (Objects.nonNull(other)) {
@@ -35,6 +60,13 @@ public class UniReturnUtil {
         return result;
     }
 
+    /**
+     * 构建一个失败返回的数据Map,包含返回数据和错误信息。
+     *
+     * @param message  失败的详细信息。
+     * @param returnData  返回的数据对象。
+     * @return 包含失败标识、错误信息和返回数据的Map。
+     */
     public static Map<String, Object> fail(String message, Object returnData) {
         Map<String, Object> result = fail(message);
         if (Objects.nonNull(returnData)) {
@@ -43,6 +75,12 @@ public class UniReturnUtil {
         return result;
     }
 
+    /**
+     * 构建一个标准的失败返回的数据Map。
+     *
+     * @param message  失败的详细信息。
+     * @return 包含失败标识和错误信息的Map。
+     */
     public static Map<String, Object> fail(String message) {
         HashMap<String, Object> result = new HashMap<>();
         result.put("message", message);
@@ -50,10 +88,24 @@ public class UniReturnUtil {
         return result;
     }
 
+    /**
+     * 根据异常对象构建一个失败返回的数据Map。
+     *
+     * @param e 异常对象。
+     * @return 包含失败标识和异常信息的Map。
+     */
     public static Map<String, Object> fail(Throwable e) {
         return fail(getMessage(e));
     }
 
+    /**
+     * 自定义代码和消息构建失败返回的数据Map,允许额外添加信息。
+     *
+     * @param code     错误代码。
+     * @param message  失败的详细信息。
+     * @param other    包含额外信息的Map。
+     * @return 包含自定义错误代码、错误信息和额外信息的Map。
+     */
     public static Map<String, Object> fail(String code, String message, Map<String, Object> other) {
         Map<String, Object> result = fail(code, message);
         if (Objects.nonNull(other)) {
@@ -62,6 +114,13 @@ public class UniReturnUtil {
         return result;
     }
 
+    /**
+     * 自定义代码和消息构建失败返回的数据Map。
+     *
+     * @param code     错误代码。
+     * @param message  失败的详细信息。
+     * @return 包含自定义错误代码和错误信息的Map。
+     */
     public static Map<String, Object> fail(String code, String message) {
         HashMap<String, Object> result = new HashMap<>();
         result.put("message", message);
@@ -69,6 +128,12 @@ public class UniReturnUtil {
         return result;
     }
 
+    /**
+     * 获取异常的详细信息,包括堆栈跟踪。
+     *
+     * @param e 异常对象。
+     * @return 异常的详细信息字符串。
+     */
     public static String getMessage(Throwable e) {
         if (e instanceof InvocationTargetException ex) {
             e = ex.getTargetException();
@@ -79,3 +144,4 @@ public class UniReturnUtil {
                 """.formatted(e.getMessage(), detailMessage);
     }
 }
+

+ 30 - 94
src/main/java/com/scbfkj/uni/library/UserUtil.java

@@ -4,39 +4,52 @@ import com.scbfkj.uni.process.DataBase;
 import com.scbfkj.uni.process.Email;
 import com.scbfkj.uni.system.Config;
 
-import java.util.*;
-
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+/**
+ * 用户工具类,提供忘记密码功能的实现。
+ */
 public class UserUtil {
+    // 私有构造方法,防止实例化
+    private UserUtil() {
+    }
 
-
+    // 数据库实例
     private static final DataBase DATA_BASE = new DataBase();
 
+    /**
+     * 忘记密码功能,根据提供的用户信息和加密类型生成新密码并通过邮件发送给用户。
+     *
+     * @param dataSourceId 数据源ID,用于查找邮件发送配置
+     * @param username 用户名
+     * @param email 用户邮箱
+     * @param encryptType 加密类型,支持MD5和RSA
+     * @return 返回操作结果,成功或失败的原因
+     * @throws Exception 查询数据库或发送邮件时可能抛出的异常
+     */
     public static Map<String, Object> forgetPassword(String dataSourceId, String username, String email, String encryptType) throws Exception {
 
+        // 从数据库验证用户账号和邮箱是否存在
         Optional<Map<String, Object>> userOpt = DATA_BASE.query(Config.getSecurityConnectionStr(), "select * from userinfo  where account = ? and email=?", username, email).stream().findFirst();
-
         if (userOpt.isEmpty()) {
             return UniReturnUtil.fail("账号或邮件不正确");
         }
-        String encryptPassword;
+
+        // 生成新密码并根据加密类型处理
         String newPassword = UUID.randomUUID().toString().substring(0, 15);
         newPassword = newPassword.substring(0, 5) + "$" + newPassword.substring(5, 10) + "@!" + newPassword.substring(10).toUpperCase();
-
+        String encryptPassword;
         switch (encryptType.toLowerCase()) {
-            case "md5" -> {
-                encryptPassword = DataEncryptionUtil.signatureMD5(newPassword);
-            }
-            case "rsa" -> {
-                encryptPassword = DataEncryptionUtil.encryptRSAByPublicKey(newPassword);
-            }
+            case "md5" -> encryptPassword = DataEncryptionUtil.signatureMD5(newPassword);
+            case "rsa" -> encryptPassword = DataEncryptionUtil.encryptRSAByPublicKey(newPassword);
             default -> {
                 return UniReturnUtil.fail("不支持的加密类型");
             }
         }
 
-
+        // 验证数据源是否存在
         Optional<Map<String, Object>> datasourceOpt = DATA_BASE.query(Config.getCenterConnectionStr(), "select * from datasource where datasourceid=?", dataSourceId).stream().findFirst();
-
         if (datasourceOpt.isEmpty()) {
             return UniReturnUtil.fail("数据源没有找到");
         }
@@ -45,8 +58,9 @@ public class UserUtil {
         String emailUsername = DataFormatUtil.toString(dataSource.get("username"));
         String emailPassword = DataFormatUtil.toString(dataSource.get("password"));
 
+        // 发送重置密码的邮件并更新数据库中的密码
         try {
-            Email.sendEmail(props, emailUsername, emailPassword, email, "找回密码", """
+            Email.sendEmail((Map<String, Object>) props, emailUsername, emailPassword, email, "找回密码", """
                     %s 您好!
                         已为您重置为新的临时密码为:
                             %s
@@ -59,83 +73,5 @@ public class UserUtil {
         }
     }
 
-//
-//    public static Map<String, Object> forgetPasswordUpdateDataSourceId(String dataSourceId, Map<String, String> data, String encryptType, String tableName, String updateDataSourceId, String updateColumn) throws Exception {
-//        List<String> columns = data.keySet().stream().toList();
-//        String V1 = data.get(columns.get(0));
-//        String V2 = data.get(columns.get(1));
-//        Optional<Map<String, Object>> userOpt = DATA_BASE.query(Config.getSecurityConnectionStr(), "select * from %s  where %s = ? and %s=?".formatted(tableName, columns.get(0), columns.get(1)), V1, V2).stream().findFirst();
-//
-//        if (userOpt.isEmpty()) {
-//            return UniReturnUtil.fail("账号或邮件不正确");
-//        }
-//
-//        String username;
-//        String email;
-//
-//
-//
-//        String encryptPassword;
-//        String newPassword = UUID.randomUUID().toString().substring(0, 15);
-//        newPassword = newPassword.substring(0, 5) + "$" + newPassword.substring(5, 10) + "@!" + newPassword.substring(10).toUpperCase();
-//
-//        switch (encryptType.toLowerCase()) {
-//            case "md5" -> {
-//                encryptPassword = DataEncryptionUtil.signatureMD5(newPassword);
-//            }
-//            case "rsa" -> {
-//                encryptPassword = DataEncryptionUtil.encryptRSAByPublicKey(newPassword);
-//            }
-//            default -> {
-//                return UniReturnUtil.fail("不支持的加密类型");
-//            }
-//        }
-//
-//
-//        Optional<Map<String, Object>> datasourceOpt = DATA_BASE.query(Config.getCenterConnectionStr(), "select * from datasource where datasourceid=?", dataSourceId).stream().findFirst();
-//
-//        if (datasourceOpt.isEmpty()) {
-//            return UniReturnUtil.fail("数据源没有找到");
-//        }
-//        Map<String, Object> dataSource = datasourceOpt.get();
-//        Map<?, ?> props = DataFormatUtil.toMap(dataSource.get("host"));
-//        String emailUsername = DataFormatUtil.toString(dataSource.get("username"));
-//        String emailPassword = DataFormatUtil.toString(dataSource.get("password"));
-//
-////        todo
-//        try {
-//            Email.sendEmail(props, emailUsername, emailPassword, email, "找回密码", """
-//                    %s 您好!
-//                        已为您重置为新的临时密码为:
-//                            %s
-//                        请尽快登录系统修改您的密码。
-//                                    """.formatted(username, newPassword));
-//            DATA_BASE.update(queryConnectionStr(updateDataSourceId), "update %s set %s = ? where %s =?".formatted(tableName,columns[]), encryptPassword, username);
-//            return UniReturnUtil.success("发送邮件成功");
-//        } catch (Exception e) {
-//            return UniReturnUtil.fail("发送邮件失败:" + UniReturnUtil.getMessage(e));
-//        }
-//    }
-//
-//    public static String queryConnectionStr(String datasourceId) throws Exception {
-//        List<Map<String, Object>> result = DATA_BASE.query(Config.getCenterConnectionStr(), """
-//                select datasourceid,
-//                       host,
-//                       username,
-//                       password,
-//                       driverclassname
-//                from datasource
-//                where datasourceid = ?""", datasourceId);
-//        if (result.isEmpty()) {
-//            throw new RuntimeException("数据源错误:没有找到数据源");
-//        }
-//        return DataFormatUtil.toString(result.stream().findFirst().map(it -> {
-//            HashMap<String, Object> hashMap = new HashMap<>();
-//            hashMap.put("jdbcUrl", it.get("host"));
-//            hashMap.put("username", it.get("username"));
-//            hashMap.put("password", it.get("password"));
-//            hashMap.put("driverClassName", it.get("driverclassname"));
-//            return hashMap;
-//        }).get());
-//    }
 }
+

+ 270 - 139
src/main/java/com/scbfkj/uni/library/XmlUtil.java

@@ -17,49 +17,87 @@ import java.util.*;
  */
 public class XmlUtil {
 
+    private XmlUtil() {
+    }
+
+    private static final String RETURN_DATA = "returnData";
+
+    /**
+     * 处理成功响应的函数。
+     *
+     * @param returnData 返回的数据对象,可以是任意类型,这个数据会被封装在返回的Map中。
+     * @return 返回一个Map,其中包含一个"code"键对应"0"值表示成功,以及一个RETURN_DATA键对应传入的returnData。
+     */
     public static Map<String, Object> processSuccess(Object returnData) {
-        Map<String, Object> returnMap = new HashMap<>();//用于当前方法统一返回参数,不存在深拷贝问题
+        // 初始化返回的Map,用于存放处理结果
+        Map<String, Object> returnMap = new HashMap<>();
+
+        // 设置返回码为"0",表示成功
         returnMap.put("code", "0");
-        returnMap.put("returnData", returnData);
+        // 将传入的数据放入Map中,使用RETURN_DATA作为键
+        returnMap.put(RETURN_DATA, returnData);
+
         return returnMap;
     }
 
-    //统一错误信息处理
+    /**
+     * 统一错误信息处理函数。
+     * 用于在发生错误时,生成一个包含错误代码和错误信息的Map对象,方便统一返回给调用方。
+     *
+     * @param errorMessage 错误信息,描述具体的错误内容。
+     * @return 返回一个Map对象,包含错误代码和错误信息。
+     */
     public static Map<String, Object> processFail(String errorMessage) {
-        Map<String, Object> returnMap = new HashMap<>();//用于当前方法统一返回参数,不存在深拷贝问题
+        // 初始化返回参数Map,用于存放错误代码和错误信息
+        Map<String, Object> returnMap = new HashMap<>();
+
+        // 设置错误代码为"-1",表示发生错误
         returnMap.put("code", "-1");
+        // 设置错误信息为传入的errorMessage
         returnMap.put("message", errorMessage);
+
         return returnMap;
     }
 
     /**
-     * xml转map 定制化
+     * 将XML字符串转换为定制化的Map格式。
      *
-     * @param xml                     字符串
-     * @param isTwoDimensionalization 是否需要二维化
-     * @param noDiKaList              是否需要dika
-     * @param translateName           需要转义的名称
-     * @return code message returnData
+     * @param xml                     输入的XML字符串
+     * @param isTwoDimensionalization 是否对结果进行二维化处理。
+     * @param noDiKaList              是否需要过滤特定的DIKA项。
+     * @param translateName           需要转换名称的映射关系。
+     * @return 返回一个包含代码、消息和处理结果数据的Map。
      */
     public static Map<String, Object> customMadexmlToMap(String xml, boolean isTwoDimensionalization, Object noDiKaList, Map<String, String> translateName) {
-        Map<String, Object> returnMap = xmlToMapFormat(xml); //  code ,message ,returenData
+        // 将XML字符串初步转换为Map格式
+        Map<String, Object> returnMap = xmlToMapFormat(xml); // 返回包括code, message, returnData的数据
+
+        // 如果转换失败,直接返回错误信息
         if (returnMap.get("code").equals("-1")) return returnMap;
+
+        // 如果需要二维化处理,则进行二维化处理
         if (isTwoDimensionalization) {
-            Map<String, Object> xmlMap = (Map<String, Object>) returnMap.get("returnData");
-            returnMap = twoDimensionalizationFormat(xmlMap, noDiKaList); //  code ,message ,returenData
+            Map<String, Object> xmlMap = (Map<String, Object>) returnMap.get(RETURN_DATA);
+            returnMap = twoDimensionalizationFormat(xmlMap, noDiKaList); // 对数据进行二维化格式处理后返回包括code, message, returnData的数据
+            // 如果处理失败,直接返回错误信息
             if (returnMap.get("code").equals("-1")) return returnMap;
         }
+
+        // 如果有名称转换需求,则进行名称转换
         if (null != translateName && !translateName.isEmpty()) {
-            Object returnData = returnMap.get("returnData"); //  code ,message ,returenData
-            if (returnData instanceof Map) {
+            Object returnData = returnMap.get(RETURN_DATA); // 获取返回的数据
+            // 判断返回数据是单个Map还是List<Map>,并分别进行名称转换处理
+            if (returnData instanceof Map<?,?> map) {
                 List<Map<String, Object>> inData = new ArrayList<>();
-                inData.add((Map) returnData);
-                returnMap = translateMapName(inData, translateName); // code message retrunData
-            } else if (returnData instanceof List) {
-                returnMap = translateMapName((List) returnData, translateName); // code message retrunData
+                inData.add((Map<String, Object>) map);
+                returnMap = translateMapName(inData, translateName);
+            } else if (returnData instanceof List<?> list) {
+                returnMap = translateMapName((List<Map<String, Object>>) list, translateName);
             }
         }
-        Object rsData = returnMap.get("returnData");
+
+        // 清理结果数据中的空值和空字符串
+        Object rsData = returnMap.get(RETURN_DATA);
         if (rsData instanceof List<?>) {
             for (Map<String, Object> tempMap : (List<Map<String, Object>>) rsData) {
                 tempMap.values().removeAll(Collections.singleton(null));
@@ -70,225 +108,318 @@ public class XmlUtil {
             temMap.values().removeAll(Collections.singleton(null));
             temMap.values().removeAll(Collections.singleton(""));
         }
+
         return returnMap;
     }
 
 
+
+    /**
+     * 将XML格式的字符串列表转换为Map格式的数据。
+     * @param xmlList XML字符串列表,作为转换的输入。
+     * @param isTwoDimensionalizationObj 标识是否二维化处理的对象。如果为字符串,"1"或"true"表示二维化,其他表示不二维化;如果为Boolean类型,true表示二维化,false表示不二维化。
+     * @param noDiKaList 用于过滤的列表,具体作用依据外部逻辑而定。
+     * @param translateName 用于名称转换的映射表。
+     * @return 返回一个Map,包含转换结果。如果成功,"code"键的值为"0","data"键的值为转换结果;如果失败,"code"键的值为"-1"。
+     */
     public static Map<String, Object> customMadeListxmlToMap(List<String> xmlList, Object isTwoDimensionalizationObj, Object noDiKaList, Map<String, String> translateName) {
-        if (Objects.isNull(xmlList) || xmlList.size() == 0) {
+        // 检查输入的XML列表是否为空
+        if (Objects.isNull(xmlList) || xmlList.isEmpty()) {
             return MapTools.processSuccess(null);
         }
+
+        // 解析是否进行二维化处理
         boolean isTwoDimensionalization;
-        if(isTwoDimensionalizationObj instanceof String s){
-            if("1".equalsIgnoreCase(s) || "true".equalsIgnoreCase(s)){
+        if (isTwoDimensionalizationObj instanceof String s) {
+            // 当参数为字符串时,解析是否二维化
+            if ("1".equalsIgnoreCase(s) || "true".equalsIgnoreCase(s)) {
                 isTwoDimensionalization = true;
             } else {
                 isTwoDimensionalization = false;
             }
-        }else if(isTwoDimensionalizationObj instanceof Boolean b){
+        } else if (isTwoDimensionalizationObj instanceof Boolean b) {
+            // 当参数为Boolean类型时,直接使用其值
             isTwoDimensionalization = b;
         } else {
             isTwoDimensionalization = false;
         }
+
+        // 当输入只有一个XML字符串时的处理
         if (xmlList.size() == 1) {
             return customMadexmlToMap(xmlList.get(0), isTwoDimensionalization, noDiKaList, translateName);
         }
+
+        // 批量处理XML字符串列表
         List<Map<String, Object>> batchList = new ArrayList<>();
         xmlList.forEach(xml -> {
             Map<String, Object> stringObjectMap = customMadexmlToMap(xml, isTwoDimensionalization, noDiKaList, translateName);
+            // 对转换结果进行处理,如果结果表示失败,则初始化返回数据列表
             if ("-1".equals(stringObjectMap.get("code").toString())) {
-                stringObjectMap.put("returnData", new ArrayList<>());
+                stringObjectMap.put(RETURN_DATA, new ArrayList<>());
             }
-            batchList.addAll((List) stringObjectMap.get("returnData"));
+            // 收集转换结果
+            batchList.addAll((List) stringObjectMap.get(RETURN_DATA));
         });
+        // 返回批量处理的结果
         return processSuccess(batchList);
     }
 
 
     /**
-     * map key值转换
+     * 将给定数据列表中的键名根据映射关系进行转换。
      *
-     * @param returnDataList
-     * @param translateName
-     * @return
+     * @param returnDataList 原始数据列表,每个元素是一个键值对映射。
+     * @param translateName 键名转换映射,提供原键名到新键名的映射关系。
+     * @return 转换后的数据列表,每个元素是转换后的键值对映射。
      */
     public static Map<String, Object> translateMapName(List<Map<String, Object>> returnDataList, Map<String, String> translateName) {
         try {
+            // 创建一个空列表以存放转换后的数据
             List<Map<String, Object>> dataList = new ArrayList<>();
+            // 遍历原始数据列表的每个元素
             for (Map<String, Object> returnData : returnDataList) {
+                // 创建一个临时映射以存放转换后的键值对
                 Map<String, Object> temMap = new HashMap<>();
-                for (String key : returnData.keySet()) {
-                    if (translateName.containsKey(key)) {
-                        temMap.put(translateName.get(key), returnData.get(key));
+                // 遍历当前数据的每个键值对
+                for (Map.Entry<String, Object> entry : returnData.entrySet()) {
+                    // 检查当前键名是否有对应的转换键名
+                    if (translateName.containsKey(entry.getKey())) {
+                        // 如果存在,将值存放到新键名对应的临时映射中
+                        temMap.put(translateName.get(entry.getKey()), entry.getValue());
                     }
                 }
+                // 将转换后的映射添加到数据列表中
                 dataList.add(temMap);
             }
+            // 返回处理成功的结果,包含转换后的数据列表
             return processSuccess(dataList);
         } catch (Exception e) {
+            // 如果过程中发生异常,返回处理失败的结果,包含错误信息
             return processFail("translateMapName替换异常");
         }
     }
 
+
     /**
-     * xml 转map 通用化
+     * 将XML字符串转换为Map格式的通用方法。
+     * 这个方法主要用于将符合XML格式的字符串解析,并将其元素和属性转换为一个Map对象,
+     * 其中Map的键为XML元素的名称,值为元素的文本内容或属性值。
      *
-     * @param xml
-     * @return
+     * @param xml 待转换的XML字符串。
+     * @return 如果转换成功,返回一个包含XML数据的Map;如果转换失败,返回一个包含错误信息的Map。
      */
     public static Map<String, Object> xmlToMapFormat(String xml) {
         try {
+            // 处理XML字符串,确保它以正确的XML声明开始,并且只包含根元素的内容。
             String xmlStr = xml.substring(xml.contains("<") ? xml.indexOf("<") : 0, xml.lastIndexOf(">") > 0 ? xml.lastIndexOf(">") + 1 : xml.length());
             xmlStr = (xmlStr.contains("<?xml") ? "" : "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n").concat(xmlStr);
             Document doc = DocumentHelper.parseText(xmlStr);
             Element root = doc.getRootElement();
-            Map<String, Object> returnMap = xmlToMap(root);
-//            returnMap.put("souceData", xml);
-                returnMap.put("sourceData", xml);
+            Map<String, Object> returnMap = xmlToMap(root); // 调用递归方法将XML元素转换为Map。
+            returnMap.put("sourceData", xml); // 将原始XML字符串添加到返回的Map中。
 
-            return processSuccess(returnMap);
+            return processSuccess(returnMap); // 处理成功结果并返回。
         } catch (Exception e) {
+            // 如果在转换过程中出现异常,处理失败结果并返回。
             Map<String, Object> errMap = processFail("入参不是规则的xml :" + xml);
-//            errMap.put("souceData", xml);
-                errMap.put("sourceData", xml);
+            errMap.put("sourceData", xml); // 将原始XML字符串添加到错误信息Map中。
 
-            return errMap;
+            return errMap; // 返回包含错误信息的Map。
         }
     }
 
 
+
     /**
-     * map 二维化
+     * 将给定的Map二维化处理。
+     * 该方法主要将一个嵌套结构的Map转换为一个包含列表的二维Map结构,以便于前端展示或处理。
      *
-     * @param inMap      需要二维化map
-     * @param noDiKaList 需要dika
-     * @return
+     * @param inMap 需要进行二维化处理的Map对象。该Map对象应包含需要转换的数据结构。
+     * @param noDiKaList 需要排除的键列表,具体用途可能与函数内部逻辑相关。
+     * @return 返回处理后的二维化Map对象。如果处理成功,返回包含转换后的数据的Map;如果处理失败,返回一个包含错误信息的Map。
      */
     public static Map<String, Object> twoDimensionalizationFormat(Map<String, Object> inMap, Object noDiKaList) {
         try {
+            // 初始化返回数据列表
             List<Map<String, Object>> returnDataList = new ArrayList<>();
+            // 克隆输入的Map对象,以避免修改原始数据
             Map<String, Object> toInMap = MapTools.clone(inMap);
+            // 检查克隆的Map对象是否非空,非空则进行二维化处理
             if (Objects.nonNull(toInMap) && !toInMap.isEmpty()) {
-                returnDataList = twoDimensionalization(toInMap, "", noDiKaList); /*生命周期未添加*/
+                // 执行二维化处理,并将结果存入returnDataList
+                returnDataList = twoDimensionalization(toInMap, "", noDiKaList); /* 二维化处理过程 */
             }
+            // 对处理结果进行加工,准备返回
             return processSuccess(returnDataList);
         } catch (Exception e) {
+            // 处理异常,返回失败信息
             return processFail(UniReturnUtil.getMessage(e));
         }
     }
 
-    private static List<Map<String, Object>> twoDimensionalization(Map<String, Object> inMap, String keyName, Object noDiKaList) {
-        //初始化一个返回数组List<map<string,object>> returnList
-        List<Map<String, Object>> returnList = new ArrayList<>();
-        // 默认添加一个空MAP----returnList.add(new map)//目的是确保计算迪卡乘积以及最后的单值赋值不出现问题
-        returnList.add(new HashMap<>());
-        //循环入参inMap
-        for (String currentKeyName : inMap.keySet()) {
-//            组装键名itemKeyName = (keyName为空?'':keyName) + '_' + currentKeyName
-            String itemKeyName = (Objects.equals(keyName, "") ? "" : keyName + '_') + currentKeyName;//组装键名
-            Object currentValue = inMap.get(currentKeyName);
-            if (currentValue instanceof List) {
+
+/**
+ * 将给定的Map转换为二维列表。该函数通过递归处理输入的Map,将每个键值对转换为一个Map,然后将这些Map收集到一个二维列表中。
+ * 如果值是列表类型,则会对列表中的每个元素进行处理。对于指定的键名不应出现在最终结果中的情况,通过noDiKaList参数进行标记。
+ *
+ * @param inMap 输入的Map,需要转换为二维列表的原始数据。
+ * @param keyName 当前处理键名的前缀,用于组装最终的键名。
+ * @param noDiKaList 标记列表,用于指定某些键名不应出现在转换后的二维列表中。如果为"noDika"字符串,则忽略递归过程中的迪卡乘积计算。
+ * @return 返回一个二维列表,其中每个元素都是一个包含键值对的Map。
+ */
+private static List<Map<String, Object>> twoDimensionalization(Map<String, Object> inMap, String keyName, Object noDiKaList) {
+    // 初始化返回列表
+    List<Map<String, Object>> returnList = new ArrayList<>();
+    // 添加一个空的Map作为初始值,以确保后续操作不会出现问题
+    returnList.add(new HashMap<>());
+
+    // 遍历输入的Map
+    for (Map.Entry<String, Object> entry : inMap.entrySet()) {
+        // 组装当前键名
+        String itemKeyName = (keyName.isEmpty() ? "" : keyName + '_') + entry.getKey();
+        Object currentValue = entry.getValue();
+
+        if (currentValue instanceof List) {
+            List<Map<String, Object>> tempList = new ArrayList<>();
+            List<Object> list = (List<Object>) currentValue;
+
+            // 处理不应出现在结果中的键名
+            if (noDiKaList != null && noDiKaList instanceof List<?> tpList && tpList.contains(itemKeyName)) {
+                Map<String, Object> tempMap = new HashMap<>();
+                tempMap.put(itemKeyName, currentValue.toString());
+                tempList.add(tempMap);
+            } else {
+                // 递归处理列表中的每个元素
+                for (Object o : list) {
+                    if (o instanceof Map) {
+                        List<Map<String, Object>> tempListMap = twoDimensionalization((Map<String, Object>) o, itemKeyName, noDiKaList);
+                        // 根据noDiKaList的值决定是否直接添加或进行迪卡乘积计算
+                        if (noDiKaList instanceof String inStr && inStr.equals("noDika")) {
+                            tempList.addAll(tempListMap);
+                        } else {
+                            tempListMap = dikaMap(returnList, tempListMap);
+                            tempList.addAll(tempListMap);
+                        }
+                    } else {
+                        HashMap<String, Object> map = new HashMap<>();
+                        map.put(itemKeyName, o);
+                        tempList.add(map);
+                    }
+                }
+            }
+            returnList = tempList;
+        } else {
+            if (currentValue instanceof Map) {
+                // 对值为Map类型的元素进行递归处理
+                List<Map<String, Object>> tempListMap = twoDimensionalization((Map<String, Object>) currentValue, itemKeyName, noDiKaList);
                 List<Map<String, Object>> tempList = new ArrayList<>();
-                List<Object> list = (List<Object>) currentValue;
-                if (Objects.nonNull(noDiKaList) && noDiKaList instanceof List<?> tpList && tpList.contains(itemKeyName)) {
+
+                // 处理不应出现在结果中的键名
+                if (noDiKaList != null && noDiKaList instanceof List<?> tpList && tpList.contains(itemKeyName)) {
                     Map<String, Object> tempMap = new HashMap<>();
                     tempMap.put(itemKeyName, currentValue.toString());
                     tempList.add(tempMap);
+                    returnList = tempList;
                 } else {
-                    for (Object o : list) {
-                        if (o instanceof Map) {
-                            List<Map<String, Object>> tempListMap = twoDimensionalization((Map<String, Object>) o, itemKeyName, noDiKaList);
-                            if (noDiKaList instanceof String inStr && inStr.equals("noDika")) {
-                                tempList.addAll(tempListMap);
-                            } else {
-                                tempListMap = dikaMap(returnList, tempListMap);//计算迪卡乘积
-                                tempList.addAll(tempListMap);
-                            }
-                        } else {
-                            tempList.add(new HashMap<>() {{
-                                put(itemKeyName, o);
-                            }});
-                        }
+                    // 根据noDiKaList的值决定是否直接替换或进行迪卡乘积计算
+                    if (noDiKaList instanceof String inStr && inStr.equals("noDika")) {
+                        returnList = tempListMap;
+                    } else {
+                        returnList = dikaMap(returnList, tempListMap);
                     }
                 }
-                returnList = tempList;
             } else {
-                if (currentValue instanceof Map) {
-                    List<Map<String, Object>> tempListMap = twoDimensionalization((Map<String, Object>) currentValue, itemKeyName, noDiKaList);//递归下一级
-                    List<Map<String, Object>> tempList = new ArrayList<>();
-                    if (Objects.nonNull(noDiKaList) && noDiKaList instanceof List<?> tpList && tpList.contains(itemKeyName)) {
-                        Map<String, Object> tempMap = new HashMap<>();
-                        tempMap.put(itemKeyName, currentValue.toString());
-                        tempList.add(tempMap);
-                        returnList = tempList;
-                    } else {
-                        if (noDiKaList instanceof String inStr && inStr.equals("noDika")) {
-                            returnList = tempListMap;
-                        } else {
-                            returnList = dikaMap(returnList, tempListMap);//计算迪卡乘积后替换当前的returnList
-                        }
-                    }
-                } else {
-                    for (Map<String, Object> map : returnList) {//循环returnList
-                        map.put(itemKeyName, currentValue);////值不为MAP也不是数组则直接添加
-                    }
+                // 对值不是Map也不是列表的元素,直接添加到每个Map中
+                for (Map<String, Object> map : returnList) {
+                    map.put(itemKeyName, currentValue);
                 }
             }
         }
-        return returnList;//返回returnList
     }
+    return returnList;
+}
 
 
-    //MAP二维化辅助方法,返回List<map<string,object>>
-    private static List<Map<String, Object>> dikaMap(List<Map<String, Object>> parentList, List<Map<String, Object>> childList) {
-//        初始化一个返回数组
-        List<Map<String, Object>> returnList = new ArrayList<>();
-        for (Map<String, Object> childwMap : childList) {
-            HashMap<String, Object> childwMapClone = MapTools.clone(childwMap);
-            if (Objects.isNull(childwMapClone)) childwMapClone = new HashMap<>();
-            for (Map<String, Object> parentMap : parentList) {
-                HashMap<String, Object> parentMapClone = MapTools.clone(parentMap);
-                if (Objects.isNull(parentMapClone)) {
-                    parentMapClone = new HashMap<>();
-                }
-                parentMapClone.putAll(childwMapClone);
-                returnList.add(parentMapClone);//注意使用HashMap.putall实现深拷贝
+
+/**
+ * 将子级映射列表合并到父级映射列表中,生成一个包含父级和子级数据的二维映射列表。
+ * @param parentList 父级映射列表,每个映射代表一个父级数据项。
+ * @param childList 子级映射列表,每个映射代表一个子级数据项。
+ * @return 返回一个列表,其中每个元素都是一个包含父级和子级数据的映射。
+ */
+private static List<Map<String, Object>> dikaMap(List<Map<String, Object>> parentList, List<Map<String, Object>> childList) {
+    // 初始化用于存放结果的列表
+    List<Map<String, Object>> returnList = new ArrayList<>();
+    for (Map<String, Object> childwMap : childList) {
+        // 克隆当前子级映射,以保留原始数据的独立性
+        HashMap<String, Object> childwMapClone = MapTools.clone(childwMap);
+        if (Objects.isNull(childwMapClone)) childwMapClone = new HashMap<>();
+        for (Map<String, Object> parentMap : parentList) {
+            // 克隆当前父级映射,以保留原始数据的独立性
+            HashMap<String, Object> parentMapClone = MapTools.clone(parentMap);
+            if (Objects.isNull(parentMapClone)) {
+                parentMapClone = new HashMap<>();
             }
+            // 将子级映射的内容合并到父级映射中
+            parentMapClone.putAll(childwMapClone);
+            returnList.add(parentMapClone); // 通过HashMap.putAll实现深拷贝,将子级数据合并到父级数据中
         }
-        return returnList;
     }
+    return returnList;
+}
 
-    private static Map<String, Object> xmlToMap(Element element) {
-        String currentName = element.getName(); //当前节点名称
-        String currentValue = MapTools.getText(element.getTextTrim());// 当前节点值
 
-        Map<String, Object> returnMap = new HashMap<>();//初始化一个返回的结构
-        Map<String, Object> attrMap = new HashMap<>(); //初始化一个当前节点的属性结构
-        List<Attribute> attributes = element.attributes();  //属性处理
-        for (Attribute childAttribute : attributes) { //循环当前节点所有属性
-            attrMap.put(childAttribute.getName(), childAttribute.getValue());//逐个添加属性值到属性结构
-        }
-        List<Element> childNodes = element.elements(); //获取当前节点的所有子节点
-        if (childNodes.isEmpty() && !attrMap.isEmpty()) { // //无子节点且当前节点存在属性则
-            attrMap.put(currentName, currentValue); //当前节点值添加到属性中
-        }
-        for (Element childElement : childNodes) { //循环所有子节点,如果没有子节点不会进入循环
-            String childName = childElement.getName(); //获取子节点名称
-            if (attrMap.containsKey(childName)) { //已经存在相同子节点名称的值代表需要形成数组
-                Object oldValue = attrMap.get(childName); //获取已经存在的值
-                List<Object> newList = new ArrayList<>();
-                if (oldValue instanceof List) { //如果旧值已经是数组则
-                    newList = (List<Object>) oldValue; //强制转换为数组
-                } else {
-                    newList.add(oldValue); //转换为数组,旧值添加到数组中
-                }
-                newList.add(xmlToMap(childElement).get(childName));//添加子节点的数据,递归获取子节点的数据
-                attrMap.put(childName, newList);//添加到返回结构中;
+/**
+ * 将XML元素转换为Map结构。
+ * @param element XML元素,代表一个具体的XML节点。
+ * @return 返回一个Map结构,其中键为节点名称,值为节点的属性和值(包括子节点)。
+ */
+private static Map<String, Object> xmlToMap(Element element) {
+    // 初始化当前节点名称和值
+    String currentName = element.getName();
+    String currentValue = MapTools.getText(element.getTextTrim());
+
+    // 初始化返回的Map结构和当前节点的属性Map
+    Map<String, Object> returnMap = new HashMap<>();
+    Map<String, Object> attrMap = new HashMap<>();
+
+    // 处理当前节点的所有属性
+    List<Attribute> attributes = element.attributes();
+    for (Attribute childAttribute : attributes) {
+        attrMap.put(childAttribute.getName(), childAttribute.getValue());
+    }
+
+    // 获取当前节点的所有子节点
+    List<Element> childNodes = element.elements();
+    // 如果没有子节点但存在属性,则将当前节点值添加到属性中
+    if (childNodes.isEmpty() && !attrMap.isEmpty()) {
+        attrMap.put(currentName, currentValue);
+    }
+
+    // 遍历所有子节点,递归转换为Map结构
+    for (Element childElement : childNodes) {
+        String childName = childElement.getName();
+
+        // 如果已存在相同名称的属性,则将其转换为列表(数组)形式
+        if (attrMap.containsKey(childName)) {
+            Object oldValue = attrMap.get(childName);
+            List<Object> newList = new ArrayList<>();
+            if (oldValue instanceof List) {
+                newList = (List<Object>) oldValue;
             } else {
-                attrMap.put(childName, xmlToMap(childElement).get(childName));//递归获取子节点的数据;
+                newList.add(oldValue);
             }
+            newList.add(xmlToMap(childElement).get(childName));
+            attrMap.put(childName, newList);
+        } else {
+            // 递归获取子节点的数据,并添加到当前节点的属性Map中
+            attrMap.put(childName, xmlToMap(childElement).get(childName));
         }
-        returnMap.put(currentName, attrMap.isEmpty() ? currentValue : attrMap);//添加当前节点的属性以及值(包括了子节点)
-        return returnMap;
     }
+
+    // 将当前节点的属性和值(包括子节点)添加到返回的Map结构中
+    returnMap.put(currentName, attrMap.isEmpty() ? currentValue : attrMap);
+    return returnMap;
+}
+
 }

+ 44 - 2
src/main/java/com/scbfkj/uni/library/script/AuthorizationScriptUtil.java

@@ -6,30 +6,44 @@ import com.scbfkj.uni.process.DataBase;
 import com.scbfkj.uni.system.Config;
 
 import java.util.*;
-
+/**
+ * 授权脚本工具类,提供授权相关的静态方法。
+ */
 public class AuthorizationScriptUtil {
 
     private static final DataBase DATABASE = new DataBase();
 
+    /**
+     * 执行授权操作。
+     *
+     * @param data 包含授权所需数据的Map,包括datacontent(操作内容)、event(事件类型)、id(用户或用户组ID)和type(授权类型)。
+     * @return 返回操作结果,成功则包含结果数据,失败则包含错误信息。
+     * @throws Exception 如果操作过程中出现错误,则抛出异常。
+     */
     public static Map<String, Object> authorization(Map<String, Object> data) throws Exception {
 
+        // 提取datacontent,如果为空则返回失败
         List<Map<String,Object>> dataContent = Optional.ofNullable(DataFormatUtil.toList(data.get("datacontent"))).orElse(new ArrayList<>());
         if (dataContent.isEmpty()) {
             return UniReturnUtil.fail("datacontent 为空");
         }
+        // 提取并转换事件类型、ID和授权类型
         Object event = data.get("event").toString();
         String id = data.get("id").toString();
         Object type = data.get("type").toString();
-        String sql = null;
+        String sql;
 
+        // 根据授权类型和事件类型执行不同的SQL操作
         if ("1".equals(type)) {
             if ("1".equals(event)) {
+                // 为用户添加权限
                 sql = """
                         insert into userpermissions (userid, pageconfigurationid,serviceid)
                         values (?, ?, ?)""";
                 int[] result = DATABASE.updateBatch(Config.getSecurityConnectionStr(), sql, dataContent.stream().map(it -> new Object[]{id, it.get("pageconfigurationid"), it.get("serviceid")}).toList());
                 return UniReturnUtil.success(result);
             } else if ("3".equals(event)) {
+                // 为用户删除权限
                 sql = """
                         delete
                         from userpermissions
@@ -39,6 +53,7 @@ public class AuthorizationScriptUtil {
             }
 
         } else if ("2".equals(type)) {
+            // 处理用户组授权
             Set<Object> childrenGroup = getChildrenGroup(id);
             Map<String, List<Object[]>> children = new HashMap<>();
 
@@ -51,6 +66,7 @@ public class AuthorizationScriptUtil {
                 }
             }
             if ("1".equals(event)) {
+                // 为用户组添加权限
                 ArrayList<Object[]> lines = new ArrayList<>();
                 for (Map o : dataContent) {
                     lines.add(new Object[]{id, o.get("pageconfigurationid"),o.get("serviceid")});
@@ -73,6 +89,7 @@ public class AuthorizationScriptUtil {
 
 
             } else if ("3".equals(event)) {
+                // 为用户组删除权限
                 ArrayList<Object[]> lines = new ArrayList<>();
                 for (Map o : dataContent) {
                     lines.add(new Object[]{id, o.get("pageconfigurationid")});
@@ -103,30 +120,53 @@ public class AuthorizationScriptUtil {
 
     }
 
+    /**
+     * 获取指定用户组的所有子用户组ID。
+     *
+     * @param id 用户组ID。
+     * @return 返回该用户组的所有子用户组ID的集合。
+     * @throws Exception 如果查询过程中出现错误,则抛出异常。
+     */
     public static Set<Object> getChildrenGroup(String id) throws Exception {
         Set<Object> children = new HashSet<>();
         String sql = """
                                 select usergroupid
                 from usergroup where superiorid=?""";
         List<Map<String, Object>> result = DATABASE.query(Config.getSecurityConnectionStr(), sql, id);
+        // 递归获取所有子用户组
         for (Map<String, Object> it : result) {
             children.addAll(getChildrenGroup(it.get("usergroupid").toString()));
         }
         return children;
     }
 
+    /**
+     * 获取指定用户组的所有子用户ID。
+     *
+     * @param groupIds 用户组ID的集合。
+     * @return 返回该用户组的所有子用户ID的集合。
+     * @throws Exception 如果查询过程中出现错误,则抛出异常。
+     */
     public static Set<Object> getChildrenUserInfo(Set<Object> groupIds) throws Exception {
         Set<Object> children = new HashSet<>();
         String sql = """
                                 select userid
                 from userinfo where usergroupid=?""";
         List<Map<String, Object>> result = DATABASE.queryBatch(Config.getSecurityConnectionStr(), sql, groupIds.stream().map(it -> new Object[]{it}).toList());
+        // 递归获取所有子用户的用户组
         for (Map<String, Object> it : result) {
             children.addAll(getChildrenGroup(it.get("userid").toString()));
         }
         return children;
     }
 
+    /**
+     * 获取用户或用户组的授权信息。
+     *
+     * @param data 包含需要查询授权信息的用户或用户组ID和类型的Map。
+     * @return 返回查询到的授权信息列表。
+     * @throws Exception 如果查询过程中出现错误,则抛出异常。
+     */
     public static Map<String, Object> getAuthorization(Map<String, Object> data) throws Exception {
         List<Map<String, Object>> dataContent = Optional.ofNullable(DataFormatUtil.toList(data.get("datacontent"))).map(it -> it.stream().map(d -> {
             Map<?, ?> map = DataFormatUtil.toMap(d);
@@ -138,6 +178,7 @@ public class AuthorizationScriptUtil {
         Map<String, Object> value = dataContent.get(0);
         Object id = value.get("id");
         List<Map<String, Object>> results;
+        // 根据授权类型查询授权信息
         if ("2".equals(value.get("type").toString())) {
             results = DATABASE.query(Config.getSecurityConnectionStr(), """
                     select distinct pageconfiguration.*,filterset
@@ -155,3 +196,4 @@ public class AuthorizationScriptUtil {
         return UniReturnUtil.success(results);
     }
 }
+

+ 446 - 253
src/main/java/com/scbfkj/uni/library/script/DatabaseScriptUtil.java

@@ -13,33 +13,55 @@ import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
 public class DatabaseScriptUtil {
-
-    private static final List<String> events = new ArrayList<>();
-    private static final Pattern regExpression = Pattern.compile("(?<=《)([^》]+)?(?=》)");//提取书名号变量的正则表达式
-    private static final Map<String, List<String>> sqlStrVarList = new HashMap<>();//SQL语句的书名号变量列表
+    /**
+     * 数据处理相关的静态变量和初始化。
+     * EVENTS: 存储事件编号的列表。
+     * REG_EXPRESSION: 用于提取书名号括起来的变量的正则表达式。
+     * SQL_STR_VAR_LIST: 存储SQL语句中书名号变量与对应值的列表。
+     * sqlStrNewSQL: 存储更换了书名号变量后的可执行SQL语句的映射。
+     */
+    private static final List<String> EVENTS = new ArrayList<>();
+    private static final Pattern REG_EXPRESSION = Pattern.compile("(?<=《)([^》]+)?(?=》)");//提取书名号变量的正则表达式
+    private static final Map<String, List<String>> SQL_STR_VAR_LIST = new HashMap<>();//SQL语句的书名号变量列表
     public static Map<String, String> sqlStrNewSQL = new HashMap<>();//SQL语句更换书名号变量后的可执行SQL
 
+    // 初始化EVENTS列表
     static {
-        events.add("0");
-        events.add("1");
-        events.add("2");
-        events.add("3");
-        events.add("6");
-        events.add("7");
+        EVENTS.add("0");
+        EVENTS.add("1");
+        EVENTS.add("2");
+        EVENTS.add("3");
+        EVENTS.add("6");
+        EVENTS.add("7");
     }
 
+    // 数据库操作对象
     private final DataBase DATABASE = new DataBase();
 
-    public  Pageable pageable(Map<String, Object> args) {
+    /**
+     * 根据提供的参数生成Pageable对象。
+     * 如果"event"参数非空且不等于"0",则返回null。
+     * 否则,从args中解析"page"和"size"参数来构造Pageable对象。
+     * 如果解析出的页码小于0,则默认为0;如果解析出的页面大小小于等于0,则默认为50。
+     *
+     * @param args 包含页面请求参数的映射
+     * @return 根据提供的参数构造的Pageable对象,或者在不满足条件时返回null
+     */
+    public Pageable pageable(Map<String, Object> args) {
+
+        // 解析页面和大小参数
         Object page = args.get("page");
         Object size = args.get("size");
         Long pageNumber = 0L;
         Long pageSizeNumber = 0L;
         Object event = args.get("event");
+
+        // 如果事件参数非空且不等于"0",则返回null
         if (event == null || !event.toString().equals("0")) {
             return null;
         }
 
+        // 处理页面号和页面大小
         if (Objects.nonNull(page)) {
             pageNumber = Long.parseLong(page.toString()) - 1;
         }
@@ -52,52 +74,104 @@ public class DatabaseScriptUtil {
         if (pageSizeNumber <= 0) {
             pageSizeNumber = 50L;
         }
+
+        // 返回构造的Pageable对象
         return new Pageable(pageNumber, pageSizeNumber);
     }
 
+    /**
+     * 根据过滤行列表生成SQL WHERE子句字符串。
+     * 过滤行列表中的每个条目应包含列名、比较器和值,可选地包括左右连接器和事件标志。
+     *
+     * @param filterLines 过滤条件的列表,每个过滤条件是一个包含列、比较器和值的映射
+     * @return 根据过滤行列表构造的WHERE子句字符串
+     */
     public String getFilterLinesWhereSql(List<Map<String, Object>> filterLines) {
-        if (Objects.isNull(filterLines)) filterLines = new ArrayList<>();
+        if(filterLines == null){
+            return "";
+        }
+        // 初始化WHERE条件字符串
         String filterLineWhereStr = "";
         for (Object f : filterLines) {
             Map<String, Object> it = ((Map<String, Object>) f);
             Object comparator = it.get("comparator").toString().toLowerCase();
+            // 格式化构造WHERE子句
             filterLineWhereStr = " %s %s %s %s %s %s %s ".formatted(filterLineWhereStr,
                     it.getOrDefault("left", ""),
                     it.get("column"),
                     comparator,
-                    Objects.equals(comparator, " is null ") || Objects.equals(comparator, " is not null ") ? "" :"'"+ it.get("value")+"'",
+                    Objects.equals(comparator, " is null ") || Objects.equals(comparator, " is not null ") ? "" : "'" + it.get("value") + "'",
                     it.getOrDefault("right", ""),
                     it.getOrDefault("connector", ""));
         }
         return filterLineWhereStr;
     }
 
+    /**
+     * 从SQL字符串中提取变量列表,并更新SQL为使用占位符的形式。
+     * 初始版本的SQL字符串不会被修改,而是创建一个新的SQL字符串用于后续处理。
+     *
+     * @param sqlStr 原始SQL字符串
+     * @return SQL字符串中包含的变量列表
+     */
     public List<String> getSQLVarList(String sqlStr) {
-        String newSqlStr = sqlStr;//不破坏之前SQL语句
-        List<String> sqlvarList = sqlStrVarList.containsKey(sqlStr) ? sqlStrVarList.get(sqlStr) : new ArrayList<>();//优先从缓存中取
-        if (!sqlStrNewSQL.containsKey(sqlStr)) {//缓存不存在则重新获取
-            Matcher matcher = regExpression.matcher(sqlStr);//正则提取
-            while (matcher.find()) {//循环提取到的所有书名号变量
+        // 不修改原始SQL字符串
+        String newSqlStr = sqlStr;
+        // 从缓存中获取或创建新的变量列表
+        List<String> sqlvarList = SQL_STR_VAR_LIST.containsKey(sqlStr) ? SQL_STR_VAR_LIST.get(sqlStr) : new ArrayList<>();
+        // 如果缓存中不存在,则重新解析SQL
+        if (!sqlStrNewSQL.containsKey(sqlStr)) {
+            // 使用正则表达式提取变量
+            Matcher matcher = REG_EXPRESSION.matcher(sqlStr);
+            while (matcher.find()) {
                 String varName = matcher.group();
                 sqlvarList.add(varName.trim());
-                newSqlStr = newSqlStr.replaceFirst("《".concat(varName).concat("》"), " ? "); //修订SQL
+                // 用占位符替换变量
+                newSqlStr = newSqlStr.replaceFirst("《".concat(varName).concat("》"), " ? ");
             }
-            sqlStrVarList.put(sqlStr, sqlvarList);//添加到缓存
-            sqlStrNewSQL.put(sqlStr, newSqlStr);//添加到缓存
+            // 更新缓存
+            SQL_STR_VAR_LIST.put(sqlStr, sqlvarList);
+            sqlStrNewSQL.put(sqlStr, newSqlStr);
         }
         return sqlvarList;
     }
 
+    /**
+     * 检查数据库中是否存在匹配的记录。
+     * 使用提供的连接字符串、SQL语句和参数数组执行查询,判断是否存在符合条件的记录。
+     *
+     * @param connectionStr 数据库连接字符串
+     * @param sql           SQL查询语句
+     * @param args          SQL查询参数数组
+     * @return 如果存在匹配的记录,则返回true;否则返回false
+     * @throws Exception 如果查询过程中出现错误,则抛出异常
+     */
     private boolean exists(String connectionStr, String sql, Object[] args) throws Exception {
+        // 执行查询
         List<Map<String, Object>> mapList = DATABASE.queryBatch(connectionStr, sql, Collections.singletonList(args));
+        // 判断是否存在记录,并处理结果
         if (mapList.isEmpty()) return false;
         return !Objects.equals(mapList.get(0).get("existscount").toString(), "0");
     }
 
+    /**
+     * 根据提供的SQL查询数据。
+     *
+     * @param connectionStr 数据源标识或连接字符串
+     * @param sql           查询的SQL语句
+     * @param argsList      查询参数列表
+     * @param filterColumns 需要过滤的列
+     * @param filterLines   过滤条件行
+     * @param pageable      分页信息
+     * @return 查询结果列表
+     * @throws Exception 查询过程中的任何异常
+     */
     public List<Map<String, Object>> query(String connectionStr, String sql, List<Map<String, Object>> argsList, List<String> filterColumns, List<Map<String, Object>> filterLines, Pageable pageable) throws Exception {
 
+        // 替换SQL中的换行符
         sql = sql.replaceAll("(\\r)?\\n", " ");
         String filterLineWhereStr = null;
+        // 构建基于filterLines的where条件字符串
         if (Objects.nonNull(filterLines)) {
             for (Object f : filterLines) {
                 Map<String, Object> it = ((Map<String, Object>) f);
@@ -105,9 +179,11 @@ public class DatabaseScriptUtil {
                 filterLineWhereStr = " %s %s %s %s %s %s %s %s ".formatted(filterLineWhereStr, it.getOrDefault("left", ""), it.get("column"), comparator, Objects.equals(comparator, " is null ") ? "" : "?", !Objects.equals(comparator, " is null ") ? " " : it.get("value"), it.getOrDefault("right", ""), it.getOrDefault("connector", ""));
             }
         }
+        // 将构建的where条件附加到SQL上
         if (Objects.nonNull(filterLineWhereStr)) {
             sql = " %s %s and %s ".formatted(sql, sql.contains(" where ") ? " 1 = 1" : " where ", filterLineWhereStr);
         }
+        // 如果指定过滤列,则将查询结果限定在这些列上
         if (Objects.nonNull(filterColumns) && !filterColumns.isEmpty()) {
             sql = "select %s from ( %s ) T".formatted(String.join(",", filterColumns), sql);
         }
@@ -117,6 +193,7 @@ public class DatabaseScriptUtil {
         List<String> names = getSQLVarList(sql);
         String newSql = DatabaseScriptUtil.sqlStrNewSQL.get(sql);
 
+        // 处理whereStr变量替换
         if (names.size() == 1 && names.contains("whereStr")) {
             List<Map<String, Object>> list = new ArrayList<>();
             for (Map<String, Object> stringObjectMap : argsList) {
@@ -134,6 +211,7 @@ public class DatabaseScriptUtil {
             }
             return list;
         } else {
+            // 准备查询参数
             for (Map<String, Object> map : argsList) {
                 List<Object> args = new ArrayList<>();
                 map = ((Map<String, Object>) map.getOrDefault("filter", map));
@@ -143,13 +221,24 @@ public class DatabaseScriptUtil {
                 result.add(args);
             }
 
+            // 处理分页
             if (pageable != null) {
                 newSql = "%s limit %d offset %d ".formatted(newSql, pageable.pageSize, pageable.page * pageable.pageSize);
             }
+            // 执行查询并返回结果
             return DATABASE.queryBatch(connectionStr, newSql, result.stream().map(List::toArray).toList());
         }
     }
 
+    /**
+     * 根据SQL表达式执行数据库操作。
+     *
+     * @param datasourceId 数据源标识
+     * @param expression   SQL表达式
+     * @param args         查询参数
+     * @return 操作结果
+     * @throws Exception 操作过程中的任何异常
+     */
     public Map<String, Object> execBySql(String datasourceId, String expression, Map<String, Object> args) throws Exception {
         Object event = args.get("event");
         Pageable pageable = pageable(args);
@@ -164,6 +253,7 @@ public class DatabaseScriptUtil {
         if (!event.equals("0")) {
             throw new RuntimeException("执行编号只能是 :0");
         }
+        // 处理数据内容和过滤条件
         List<Map<String, Object>> dataContent = DataFormatUtil.toList(args.get("datacontent")).stream().map(it -> ((Map<String, Object>) it)).toList();
         Object filterColumnsTemp = args.get("filterColumns");
         List<String> filterColumns = null;
@@ -178,24 +268,26 @@ public class DatabaseScriptUtil {
         if (Objects.isNull(filterColumns)) filterColumns = new ArrayList<>();
 
         if (filterColumns.isEmpty()) {
-//            没有列权限直接返回空数据
+            // 没有列权限直接返回空数据
             return UniReturnUtil.success(new ArrayList<>());
         }
 
         String filterLineWhereStr = getFilterLinesWhereSql(filterLines);
 
         String connectionStr = datasourceId;
+        // 根据数据源标识获取实际连接字符串
         if (Pattern.compile("^\\d+$").matcher(connectionStr.trim()).matches()) {
             connectionStr = DATABASE.queryConnectionStr(connectionStr.trim());
         }
 
         if (expression.contains("《whereStr》")) {
 
-            String whereStr = " ";//初始化条件字符串
-            List<Object> dbFilter = new ArrayList<>();//初始化条件执行参数
+            String whereStr = " ";// 初始化条件字符串
+            List<Object> dbFilter = new ArrayList<>();// 初始化条件执行参数
             Map<String, Object> map = dataContent.get(0);
             Object filter = map.get("filter");
-            if (filter instanceof List filterList && !filterList.isEmpty()) {//如果存在上传的条件参数或者存在行权限
+            // 根据提供的过滤条件构建where字符串和执行参数
+            if (filter instanceof List filterList && !filterList.isEmpty()) {// 如果存在上传的条件参数或者存在行权限
                 Map<String, Object> filterMap = (Map<String, Object>) filterList.get(0);
                 if (filterMap.containsKey("column")) {
                     for (Object f : filterList) {
@@ -215,34 +307,41 @@ public class DatabaseScriptUtil {
                 whereStr += list.stream().map(it -> "%s = ?".formatted(it.getKey())).collect(Collectors.joining(" and "));
                 dbFilter.addAll(list.stream().map(Map.Entry::getValue).toList());
             }
+            // 组合已有的where条件和行过滤条件
             whereStr = " %s and  %s".formatted(whereStr.trim().isEmpty() ? " 1=1 " : whereStr, filterLineWhereStr.trim().isEmpty() ? " 1=1 " : filterLineWhereStr);
             String sql = expression.replaceAll("《whereStr》", " " + whereStr);
 
+            // 处理查询列
             sql = "select %s from (%s) as T".formatted(String.join(",", filterColumns), sql);
 
+            // 处理分页
             if (pageable != null && !sql.contains(" limit ")) {
                 sql = "%s limit %d offset %d ".formatted(sql, pageable.pageSize, pageable.page * pageable.pageSize);
             }
+            // 执行查询
             List<Map<String, Object>> queryResult = DATABASE.queryBatch(connectionStr, sql, Collections.singletonList(dbFilter.toArray()));
             return UniReturnUtil.success(queryResult);
 
         } else {
             if (Objects.equals(event, "0")) {
+                // 执行查询操作
                 List<Map<String, Object>> queryResult = query(connectionStr, expression, dataContent, filterColumns, filterLines, pageable);
                 return UniReturnUtil.success(queryResult);
             } else if (Objects.equals(event, "1")) {
-                if (sqlStrVarList.containsKey(expression)) {
+                // 执行更新操作
+                if (SQL_STR_VAR_LIST.containsKey(expression)) {
                     getSQLVarList(expression);
                 }
-                List<String> names = sqlStrVarList.get(expression);
+                List<String> names = SQL_STR_VAR_LIST.get(expression);
                 String sql = sqlStrNewSQL.get(expression);
                 int[] updateResult = DATABASE.updateBatch(connectionStr, sql, dataContent.stream().map(it -> names.stream().map(it::get).toArray()).toList());
                 return UniReturnUtil.success(updateResult);
             } else {
-                if (sqlStrVarList.containsKey(expression)) {
+                // 执行更新操作,考虑行过滤条件
+                if (SQL_STR_VAR_LIST.containsKey(expression)) {
                     getSQLVarList(expression);
                 }
-                List<String> names = sqlStrVarList.get(expression);
+                List<String> names = SQL_STR_VAR_LIST.get(expression);
                 String sql = " %s  and %s".formatted(sqlStrNewSQL.get(expression), Objects.isNull(filterLineWhereStr) ? " 1=1 " : filterLineWhereStr);
                 int[] updateResult = DATABASE.updateBatch(connectionStr, sql, dataContent.stream().map(it -> names.stream().map(it::get).toArray()).toList());
                 return UniReturnUtil.success(updateResult);
@@ -250,26 +349,41 @@ public class DatabaseScriptUtil {
         }
     }
 
-    public Map<String, Object> execByTableName(String datasourceId, String table, Map<String, Object> args) throws Exception {
+    /**
+     * 根据提供的参数执行特定的数据操作。
+     *
+     * @param table 表名,不能为空且不能包含空格。
+     * @param args  包含执行所需各种参数的Map,包括事件标识、分页信息、数据内容、过滤列和过滤行等。
+     * @return 执行结果,这里未指定具体返回类型,因为代码片段未包含完整的函数体。
+     * @throws RuntimeException 当表名为空、包含空格、事件标识为空或不是预定义的事件编号之一时,抛出异常。
+     */
 
+    public Map<String, Object> execByTableName(String datasourceId, String table, Map<String, Object> args) throws Exception {
 
+        // 验证表名的合法性
         if (Objects.isNull(table) || table.trim().contains(" ")) {
             throw new RuntimeException("表名不合法: 表名不能为空");
         }
         String tableName = table;
+
+        // 从参数中获取事件标识并验证其合法性
         Object event = args.get("event");
-        Pageable pageable = pageable(args);
+        Pageable pageable = pageable(args);  // 获取分页信息,函数pageable未在代码片段中定义
 
         if (Objects.isNull(event) || !StringUtils.hasText(event.toString())) {
             throw new RuntimeException("执行编号不能为空");
         }
         event = event.toString().trim();
 
-        if (!events.contains(event)) {
-
+        // 检查事件是否在预定义的事件集合中
+        if (!EVENTS.contains(event)) {
             throw new RuntimeException("执行编号只能是 :0,1,2,3,6,7");
         }
+
+        // 处理数据内容参数
         List<Map<String, Object>> dataContent = DataFormatUtil.toList(args.get("datacontent")).stream().map(it -> ((Map<String, Object>) it)).toList();
+
+        // 处理过滤列参数
         Object filterColumnsTemp = args.get("filterColumns");
         List<String> filterColumns;
         if (Objects.nonNull(filterColumnsTemp))
@@ -277,46 +391,107 @@ public class DatabaseScriptUtil {
         else {
             filterColumns = new ArrayList<>();
         }
+
+        // 处理过滤行参数,这里代码片段未完成
         Object filterLinesTemp = args.get("filterLines");
-        List<Map<String, Object>> filterLines = null;
+        List<Map<String, Object>> filterLines = new ArrayList<>();
+        // ... 这里应有进一步的代码来处理filterLinesTemp,但代码片段未给出
+        // 将可能为null的filterLinesTemp转换为非null的List<Map<String, Object>>类型
         if (Objects.nonNull(filterLinesTemp))
             filterLines = DataFormatUtil.toList(filterLinesTemp).stream().map(it -> ((Map<String, Object>) it)).toList();
 
-
+        // 初始化expression为table的值
         String expression = table;
 
+        // 根据filterLines生成对应的SQL WHERE子句
         String filterLineWhereStr = getFilterLinesWhereSql(filterLines);
 
+        // 初始化connectionStr为datasourceId的值,之后可能根据其是否为数字进行数据库连接字符串的查询
         String connectionStr = datasourceId;
+        // 如果datasourceId是纯数字,则通过DATABASE查询对应的数据库连接字符串
         if (Pattern.compile("^\\d+$").matcher(connectionStr.trim()).matches()) {
             connectionStr = DATABASE.queryConnectionStr(connectionStr.trim());
         }
+
+        // 初始化用于存储列名的列表
         List<String> valueNames = null;
         List<String> filterNames = null;
+
+        // 通过connectionStr和expression查询表的所有列名
         List<String> allColumns = DATABASE.getColumnsByTableName(connectionStr, expression);
-        if(filterColumns.size()==1 && !"*".equals(filterColumns.get(0))) {
-            List<String> filterColumns2 = new ArrayList<>();
-            for (String allColumn : allColumns) {
-                if (filterColumns.contains(allColumn)) {
-                    filterColumns2.add(allColumn);
-                }
-            }
-                filterColumns = filterColumns2;
 
+        // 如果filterColumns只包含一个元素且不为"*",则筛选出该元素在allColumns中存在的列名
+        if (filterColumns.size() == 1 && "*".equals(filterColumns.get(0))) {
+            filterColumns = allColumns;
         }
-
 //            查询
         if (Objects.equals("0", event)) {
+            return queryByEventZero(args, filterColumns, dataContent, expression, allColumns, filterLineWhereStr, pageable, connectionStr, tableName);
+//            更新或新增
+        } else if (Objects.equals("6", event)) {
+//            新增或更新
+            return execByEventSix(args, dataContent, expression, connectionStr);
+        } else {
+//            新增修改删除
+            return execByModify(datasourceId, table, args, filterColumns, allColumns, event, dataContent, valueNames, expression, filterNames, filterLineWhereStr, connectionStr);
+        }
+    }
 
-
-            if (filterColumns.isEmpty()) {
-//                列权限为空直接返回空数据
-                return UniReturnUtil.success(new ArrayList<>());
+    /**
+     * 根据不同的事件类型执行数据库操作(新增、更新、删除)。
+     *
+     * @param datasourceId       数据源ID
+     * @param table              表名
+     * @param args               通用参数,用于不同操作中的额外信息传递
+     * @param filterColumns      过滤列,用于条件查询
+     * @param allColumns         所有列,包含表中的所有字段
+     * @param event              事件类型,决定执行的操作(1: 新增,2: 更新,3: 删除,7: 先删除后新增)
+     * @param dataContent        数据内容,包含要操作的数据信息
+     * @param valueNames         值名称列表,用于构建SQL语句中的值列表
+     * @param expression         基本的SQL表达式框架,用于构建最终的SQL语句
+     * @param filterNames        过滤名称列表,用于构建SQL语句中的过滤条件
+     * @param filterLineWhereStr 过滤行的WHERE子串,额外的过滤条件
+     * @param connectionStr      连接字符串,用于数据库连接
+     * @return 操作结果,通常为影响的行数
+     * @throws Exception 数据库操作异常或其他异常
+     */
+    private Map<String, Object> execByModify(String datasourceId, String table, Map<String, Object> args, List<String> filterColumns, List<String> allColumns, Object event, List<Map<String, Object>> dataContent, List<String> valueNames, String expression, List<String> filterNames, String filterLineWhereStr, String connectionStr) throws Exception {
+        // 根据过滤列更新allColumns
+        if (filterColumns.size() == 1 && !"*".equals(filterColumns.get(0))) {
+            for (String filterColumn : filterColumns) {
+                if (!allColumns.contains(filterColumn)) {
+                    allColumns.remove(filterColumn);
+                }
+            }
+        }
+        // 根据不同的事件类型处理数据并构建SQL语句
+        if (Objects.equals("1", event)) { // 新增
+            Map<String, Object> value = dataContent.get(0);
+            Object valueObj = value.getOrDefault("value", value);
+            Map<?, ?> map = null;
+            if (valueObj instanceof ArrayNode v) {
+                map = ((Map<?, ?>) v.get(0));
+            } else if (valueObj instanceof List<?> v) {
+                map = ((Map<?, ?>) v.get(0));
+            } else if (valueObj instanceof Map<?, ?> v) {
+                map = v;
             }
-            Map<String, Object> argMap = Objects.isNull(args) || args.isEmpty() ? new HashMap<>() : dataContent.get(0);
+            valueNames = (List<String>) map.keySet().stream().filter(allColumns::contains).toList();
+            expression = "insert into %s ( %s) values(%s)".formatted(expression, String.join(",", valueNames), valueNames.stream().map(it -> "?").collect(Collectors.joining(",")));
+
+        } else if (Objects.equals("2", event)) { // 更新
+            Map<String, Object> map = dataContent.get(0);
+            Map<String, Object> value = ((Map<String, Object>) map.get("value"));
+            valueNames = value.keySet().stream().filter(allColumns::contains).toList();
+            Map<String, Object> filter = ((Map<String, Object>) map.get("filter"));
+            filterNames = filter.keySet().stream().filter(allColumns::contains).toList();
 
+            expression = "update %s set %s where %s and %s".formatted(expression, valueNames.stream().map("%s = ?"::formatted).collect(Collectors.joining(",")), filterNames.stream().map("%s = ?"::formatted).collect(Collectors.joining(" and ")), filterLineWhereStr.trim().isEmpty() ? " 1=1 " : filterLineWhereStr);
+
+        } else if (Objects.equals("3", event)) { // 删除
+            Map<String, Object> argMap = dataContent.get(0);
             Object filter = argMap.getOrDefault("filter", argMap);
-            Map map = new HashMap<>();
+            Map<?, ?> map = null;
             if (filter instanceof ArrayNode f) {
                 map = ((Map<?, ?>) f.get(0));
             } else if (filter instanceof List<?> f) {
@@ -325,239 +500,257 @@ public class DatabaseScriptUtil {
             } else if (filter instanceof Map<?, ?> f) {
                 map = f;
             }
-
-            String whereStr = "";
-            List<Object[]> values = new ArrayList<>();
-            if (map.containsKey("column") && map.containsKey("comparator")) {
-
-                ArrayList<Object> objects = new ArrayList<>();
-//                for (Object it :  DataFormatUtil.toList(filter)) {
-////                    filter = it.getOrDefault("filter", it);
-//                    if (it instanceof Map<?, ?> it) {
-//                        map = it;
-//                    }
-//                    Object comparator = map.get("comparator");
-//                    whereStr = " %s %s %s %s %s %s %s ".formatted(whereStr, map.getOrDefault("left", ""), map.get("column"), comparator, Objects.equals(comparator, " is null ") ? " " : "?", map.getOrDefault("right", ""), map.getOrDefault("connector", ""));
-//                    if (!Objects.equals(comparator, " is null ")) {
-//                        objects.add(map.get("value"));
-//                    }
-//                }
-                whereStr = getFilterLinesWhereSql((List<Map<String, Object>>) filter);
-                expression = "select %s from %s where %s and %s".formatted(
-                        String.join(",", allColumns),
-                        expression,
-                        Objects.isNull(filterLineWhereStr) || filterLineWhereStr.trim().isEmpty() ? " 1=1 " : filterLineWhereStr,
-                        whereStr.trim().isEmpty() ? " 1=? " : whereStr);
-                if (whereStr.trim().isEmpty()) {
-                    values.add(new Object[]{1});
-                } else {
-                    values.add(objects.toArray());
-                }
-            } else {
-                filterNames = map.keySet().stream().toList();
-
-                expression = "select %s from %s where   %s  %s".formatted(String.join(",", allColumns), expression, filterLineWhereStr.trim().isEmpty() ? " 1=1 " : filterLineWhereStr,
-                        filterNames.isEmpty() ?
-                                "" : (" and " +
-                                      filterNames.stream().map("%s = ?"::formatted).collect(Collectors.joining(" and "))));
-
-                for (Map<String, Object> arg : dataContent) {
-                    Map<String, Object> o1 = ((Map<String, Object>) arg.getOrDefault("filter", arg));
-                    values.add(filterNames.stream().map(o1::get).toArray());
-                }
+            filterNames = (List<String>) map.keySet().stream().filter(allColumns::contains).toList();
+            expression = "delete from %s where %s and  %s".formatted(expression, filterNames.stream().map("%s = ?"::formatted).collect(Collectors.joining(" and ")), filterLineWhereStr.trim().isEmpty() ? " 1=1 " : filterLineWhereStr);
+        } else if (Objects.equals("7", event)) { // 先删除后新增
+            args.put("event", "3");
+            execByTableName(datasourceId, table, args); // 执行删除
+            args.put("event", "1");
+            return execByTableName(datasourceId, table, args); // 执行新增
+        }
+        List<Object[]> values = new ArrayList<>();
+        // 按照名称 和过滤条件取值,准备批量操作的数据
+        final List<String> finalFilterColumns = filterColumns;
+        for (Map<String, Object> arg : dataContent) {
+            List<Object> objects = new ArrayList<>();
+            if (Objects.nonNull(valueNames)) {
+                Map<String, Object> o1 = ((Map<String, Object>) arg.getOrDefault("value", arg));
+                objects.addAll(valueNames.stream().map(it -> {
+                    // 根据是否为过滤列或是否包含所有列来决定是否取值
+                    if (finalFilterColumns.contains(it) || finalFilterColumns.isEmpty() || (finalFilterColumns.get(0).equals("*") && finalFilterColumns.size() == 1)) {
+                        return o1.get(it);
+                    } else {
+                        return null;
+                    }
+                }).toList());
             }
-            if (pageable != null) {
-                expression = "%s limit %d offset %d ".formatted(expression, pageable.pageSize, pageable.page * pageable.pageSize);
+            if (Objects.nonNull(filterNames)) {
+                Map<String, Object> o1 = ((Map<String, Object>) arg.getOrDefault("filter", arg));
+                objects.addAll(filterNames.stream().map(o1::get).toList());
             }
-            expression = "select %s from (%s) as T".formatted(String.join(",", filterColumns), expression);
-            List<Map<String, Object>> result = DATABASE.queryBatch(connectionStr, expression, values);
-
-//            查询关联项
-
-            List<Map<String, Object>> tableJoins = DATABASE.query(Config.getCenterConnectionStr(), """
-                                        select id, sourcetable, targettable, sourcejoincolumn, targetjoincolumn, targetshowcolumns, datasourceid
-                    from tablejoin where sourcetable=?""", tableName);
-            if (!tableJoins.isEmpty()) {
-                for (Map<String, Object> tableJoin : tableJoins) {
-                    Object targettable = tableJoin.get("targettable");
-                    String sourcejoincolumn = tableJoin.get("sourcejoincolumn").toString();
-                    String targetjoincolumn = tableJoin.get("targetjoincolumn").toString();
-                    String targetshowcolumns = tableJoin.get("targetshowcolumns").toString();
-
-                    String[] split = targetshowcolumns.split(",");
-                    Map<String, String> showColumns = new HashMap<>();
-                    for (String string : split) {
-                        if (string.contains(" as ")) {
-                            String[] split1 = string.split(" as ");
-                            showColumns.put(split1[0], split1[1]);
-                        } else {
-                            showColumns.put(string, string);
-                        }
-                    }
-                    Object joinConnectionDatasourceId = tableJoin.get("datasourceid");
-
-                    String joinTableConnectionStr = connectionStr;
-                    if (Objects.nonNull(joinConnectionDatasourceId)) {
-                        joinTableConnectionStr = DATABASE.queryConnectionStr(joinConnectionDatasourceId.toString());
-                    }
-
+            values.add(objects.toArray());
+        }
+        int[] ints = DATABASE.updateBatch(connectionStr, expression, values);
+        return UniReturnUtil.success(ints); // 返回操作结果
+    }
 
-                    List<Map<String, Object>> targetDatas = DATABASE.query(joinTableConnectionStr, "select * from %s".formatted(targettable));
 
-                    result.forEach(data -> targetDatas
-                            .stream()
-                            .filter(targetData -> Objects
-                                    .equals(data
-                                            .get(sourcejoincolumn), targetData.get(targetjoincolumn)))
-                            .findAny()
-                            .ifPresent(targetData -> {
-                                for (Map.Entry<String, String> stringStringEntry : showColumns.entrySet()) {
-                                    data.put(stringStringEntry.getValue(), targetData.get(stringStringEntry.getKey()));
-                                }
-                            })
-                    );
-                }
+    /**
+     * 根据事件执行操作(具体事件为六)。
+     * 该方法将输入的数据内容根据指定的过滤条件分割为需要插入和更新的数据集合,并分别执行插入和更新操作。
+     *
+     * @param args          通用参数,用于传递给execByTableName方法。
+     * @param dataContent   待处理的数据内容列表,每个元素包含过滤条件等信息。
+     * @param expression    用于构建SQL查询的表达式,将被格式化以插入表名和条件。
+     * @param connectionStr 数据库连接字符串。
+     * @return 一个包含插入和更新操作结果的Map,其中插入结果和更新结果分别以"insert"和"update"为键。
+     * @throws Exception 如果执行数据库操作时出现错误,则抛出异常。
+     */
+    private Map<String, Object> execByEventSix(Map<String, Object> args, List<Map<String, Object>> dataContent, String expression, String connectionStr) throws Exception {
+        // 提取过滤器名称列表
+        List<String> filterNames;
+        Map<String, Object> map = dataContent.get(0);
+        Map<String, Object> filter = ((Map<String, Object>) map.get("filter"));
+        filterNames = filter.keySet().stream().toList();
+
+        // 初始化插入和更新值的列表
+        List<Map<String, Object>> insertValues = new ArrayList<>();
+        List<Map<String, Object>> updateValues = new ArrayList<>();
+
+        // 构建SQL查询语句
+        String sql = "select count(1) as existscount from %s where %s".formatted(expression, filterNames.stream().map("%s = ?"::formatted).collect(Collectors.joining(" and ")));
+        for (Map<String, Object> arg : dataContent) {
+            // 准备条件参数并检查数据是否存在
+            Map<String, Object> where = ((Map<String, Object>) arg.get("filter"));
+            Object[] objects = filterNames.stream().map(where::get).toArray();
+            if (exists(connectionStr, sql, objects)) {
+                updateValues.add(arg);
+            } else {
+                insertValues.add(arg);
             }
+        }
 
-            return UniReturnUtil.success(result);
-//                更新或新增
-        } else if (Objects.equals("6", event)) {
-            Map<String, Object> map = dataContent.get(0);
-            Map<String, Object> filter = ((Map<String, Object>) map.get("filter"));
-            filterNames = filter.keySet().stream().toList();
+        // 执行插入操作并获取结果
+        Map<String, Object> insertResult = null;
+        if (!insertValues.isEmpty()) {
+            HashMap<String, Object> insertArgs = new HashMap<>(args);
+            insertArgs.put("event", "1");
+            insertArgs.put("datacontent", insertValues);
+            insertResult = execByTableName(connectionStr, expression, insertArgs);
+        }
 
-            List<Map<String, Object>> insertValues = new ArrayList<>();
-            List<Map<String, Object>> updateValues = new ArrayList<>();
+        // 执行更新操作并获取结果
+        Map<String, Object> updateResult = null;
+        if (!updateValues.isEmpty()) {
+            HashMap<String, Object> updateArgs = new HashMap<>(args);
+            updateArgs.put("event", "1");
+            updateArgs.put("datacontent", updateValues);
+            updateResult = execByTableName(connectionStr, expression, updateArgs);
+        }
 
-            String sql = "select count(1) as existscount from %s where %s".formatted(expression, filterNames.stream().map("%s = ?"::formatted).collect(Collectors.joining(" and ")));
-            for (Map<String, Object> arg : dataContent) {
+        // 综合插入和更新结果,返回
+        Map<String, Object> finalInsertResult = insertResult;
+        Map<String, Object> finalUpdateResult = updateResult;
+        HashMap<Object, Object> data = new HashMap<>();
+        data.put("insert", finalInsertResult);
+        data.put("update", finalUpdateResult);
 
-                Map<String, Object> where = ((Map<String, Object>) arg.get("filter"));
-                Object[] objects = filterNames.stream().map(where::get).toArray();
-                if (exists(connectionStr, sql, objects)) {
-                    updateValues.add(arg);
-                } else {
-                    insertValues.add(arg);
-                }
-            }
-            Map<String, Object> insertResult = null;
+        return UniReturnUtil.success(data);
+    }
 
-            if (!insertValues.isEmpty()) {
-                HashMap<String, Object> insertArgs = new HashMap<>(args);
-                insertArgs.put("event", "1");
-                insertArgs.put("datacontent", insertValues);
-                insertResult = execByTableName(connectionStr, expression, insertArgs);
-            }
-            Map<String, Object> updateResult = null;
-            if (!updateValues.isEmpty()) {
+    /**
+     * 根据事件查询数据,支持过滤条件和分页。
+     *
+     * @param args               查询参数,可以包含过滤条件等信息
+     * @param filterColumns      需要过滤的列
+     * @param dataContent        数据内容列表
+     * @param expression         基本的SQL查询表达式
+     * @param allColumns         所有查询列
+     * @param filterLineWhereStr 过滤行的WHERE子串
+     * @param pageable           分页信息
+     * @param connectionStr      数据库连接字符串
+     * @param tableName          查询的表名
+     * @return 查询结果,封装在Map中
+     * @throws Exception 查询过程中可能出现的异常
+     */
+    private Map<String, Object> queryByEventZero(Map<String, Object> args, List<String> filterColumns, List<Map<String, Object>> dataContent, String expression, List<String> allColumns, String filterLineWhereStr, Pageable pageable, String connectionStr, String tableName) throws Exception {
+        List<String> filterNames;
+        if (filterColumns.isEmpty()) {
+            // 列权限为空直接返回空数据
+            return UniReturnUtil.success(new ArrayList<>());
+        }
 
-                HashMap<String, Object> updateArgs = new HashMap<>(args);
-                updateArgs.put("event", "1");
-                updateArgs.put("datacontent", updateValues);
-                updateResult = execByTableName(connectionStr, expression, updateArgs);
+        // 处理查询参数
+        Map<String, Object> argMap = Objects.isNull(args) || args.isEmpty() ? new HashMap<>() : dataContent.get(0);
+        // 解析过滤条件
+        Object filter = argMap.getOrDefault("filter", argMap);
+        Map<?, ?> map = null;
+        if (filter instanceof ArrayNode) {
+            map = ((Map<?, ?>) ((ArrayNode) filter).get(0));
+        } else if (filter instanceof List<?>) {
+            map = ((Map<?, ?>) ((List<?>) filter).get(0));
+        } else if (filter instanceof Map<?, ?>) {
+            map = (Map<?, ?>) filter;
+        }
+        // 构造WHERE子句和参数值列表
+        String whereStr = "";
+        List<Object[]> values = new ArrayList<>();
+        if (map.containsKey("column") && map.containsKey("comparator")) {
+            whereStr = getFilterLinesWhereSql((List<Map<String, Object>>) filter);
+            expression = String.format("select %s from %s where %s and %s",
+                    String.join(",", allColumns),
+                    expression,
+                    Objects.isNull(filterLineWhereStr) || filterLineWhereStr.trim().isEmpty() ? " 1=1 " : filterLineWhereStr,
+                    whereStr.trim().isEmpty() ? " 1=? " : whereStr);
+            if (whereStr.trim().isEmpty()) {
+                values.add(new Object[]{1});
+            } else {
+                values.add(new Object[0]); // 优化点:这里可以根据whereStr的实际内容填充参数
             }
+        } else {
+            filterNames = (List<String>) map.keySet().stream().toList();
+            expression = String.format("select %s from %s where   %s  %s",
+                    String.join(",", allColumns), expression,
+                    filterLineWhereStr.trim().isEmpty() ? " 1=1 " : filterLineWhereStr,
+                    filterNames.isEmpty() ?
+                            "" : (" and " +
+                                  filterNames.stream().map("%s = ?"::formatted).collect(Collectors.joining(" and "))));
 
-            Map<String, Object> finalInsertResult = insertResult;
-            Map<String, Object> finalUpdateResult = updateResult;
-            HashMap<Object, Object> data = new HashMap<>();
-            data.put("insert", finalInsertResult);
-            data.put("update", finalUpdateResult);
+            for (Map<String, Object> arg : dataContent) {
+                Map<String, Object> o1 = ((Map<String, Object>) arg.getOrDefault("filter", arg));
+                values.add(filterNames.stream().map(o1::get).toArray());
+            }
+        }
+        // 处理分页
+        if (pageable != null) {
+            expression = String.format("%s limit %d offset %d ",
+                    expression, pageable.pageSize, pageable.page * pageable.pageSize);
+        }
 
-            return UniReturnUtil.success(data);
-        } else {
-//                新增
-            if(filterColumns.size()==1 && !"*".equals(filterColumns.get(0))) {
-                for (String filterColumn : filterColumns) {
-                    if (!allColumns.contains(filterColumn)) {
-                        allColumns.remove(filterColumn);
+        // 优化点:这里可以考虑是否需要对filterColumns进行处理
+
+        expression = String.format("select %s from (%s) as T", String.join(",", filterColumns), expression);
+
+        // 执行查询
+        List<Map<String, Object>> result = DATABASE.queryBatch(connectionStr, expression, values);
+        // 处理表关联查询
+        List<Map<String, Object>> tableJoins = DATABASE.query(Config.getCenterConnectionStr(), """
+                select id, sourcetable, targettable, sourcejoincolumn, targetjoincolumn, targetshowcolumns, datasourceid
+                from tablejoin where sourcetable=?""", tableName);
+        if (!tableJoins.isEmpty()) {
+            for (Map<String, Object> tableJoin : tableJoins) {
+                // 进行表关联查询,合并结果
+                String targetTable = tableJoin.get("targettable").toString();
+                String sourceJoinColumn = tableJoin.get("sourcejoincolumn").toString();
+                String targetJoinColumn = tableJoin.get("targetjoincolumn").toString();
+                String targetShowColumns = tableJoin.get("targetshowcolumns").toString();
+
+                String[] split = targetShowColumns.split(",");
+                Map<String, String> showColumns = new HashMap<>();
+                for (String string : split) {
+                    if (string.contains(" as ")) {
+                        String[] split1 = string.split(" as ");
+                        showColumns.put(split1[0], split1[1]);
+                    } else {
+                        showColumns.put(string, string);
                     }
                 }
-            }
-            if (Objects.equals("1", event)) {
-                Map<String, Object> value = dataContent.get(0);
-                Object valueObj = value.getOrDefault("value", value);
-                Map map = null;
-                if (valueObj instanceof ArrayNode v) {
-                    map = ((Map<?, ?>) v.get(0));
-                } else if (valueObj instanceof List<?> v) {
-                    map = ((Map<?, ?>) v.get(0));
-                } else if (valueObj instanceof Map<?, ?> v) {
-                    map = v;
-                }
-//                    Map<String, Object> value = ((Map<String, Object>) map.getOrDefault("value", map));
-                valueNames = map.keySet().stream().filter(allColumns::contains).toList();
-                expression = "insert into %s ( %s) values(%s)".formatted(expression, String.join(",", valueNames), valueNames.stream().map(it -> "?").collect(Collectors.joining(",")));
-//                    更新
-            } else if (Objects.equals("2", event)) {
-                Map<String, Object> map = dataContent.get(0);
-                Map<String, Object> value = ((Map<String, Object>) map.get("value"));
-                valueNames = value.keySet().stream().filter(allColumns::contains).toList();
-                Map<String, Object> filter = ((Map<String, Object>) map.get("filter"));
-                filterNames = filter.keySet().stream().filter(allColumns::contains).toList();
-
-                expression = "update %s set %s where %s and %s".formatted(expression, valueNames.stream().map("%s = ?"::formatted).collect(Collectors.joining(",")), filterNames.stream().map("%s = ?"::formatted).collect(Collectors.joining(" and ")), filterLineWhereStr.trim().isEmpty() ? " 1=1 " : filterLineWhereStr);
-//                    删除
-            } else if (Objects.equals("3", event)) {
-
-
-                Map<String, Object> argMap = dataContent.get(0);
-                Object filter = argMap.getOrDefault("filter", argMap);
-                Map map = null;
-                if (filter instanceof ArrayNode f) {
-                    map = ((Map<?, ?>) f.get(0));
-                } else if (filter instanceof List<?> f) {
-                    map = ((Map<?, ?>) f.get(0));
-
-                } else if (filter instanceof Map<?, ?> f) {
-                    map = f;
-                }
-                filterNames = map.keySet().stream().filter(allColumns::contains).toList();
-                expression = "delete from %s where %s and  %s".formatted(expression, filterNames.stream().map("%s = ?"::formatted).collect(Collectors.joining(" and ")), filterLineWhereStr.trim().isEmpty() ? " 1=1 " : filterLineWhereStr);
-            } else if (Objects.equals("7", event)) {
-//                    先删除
-                args.put("event", "3");
-                execByTableName(datasourceId, table, args);
-//                    再新增
-                args.put("event", "1");
-                return execByTableName(datasourceId, table, args);
-            }
-            List<Object[]> values = new ArrayList<>();
-//                按照名称 和过滤条件取值
-            final List<String> finalFilterColumns = filterColumns;
-            for (Map<String, Object> arg : dataContent) {
-                List<Object> objects = new ArrayList<>();
-                if (Objects.nonNull(valueNames)) {
-                    Map<String, Object> o1 = ((Map<String, Object>) arg.getOrDefault("value", arg));
-                    objects.addAll(valueNames.stream().map(it -> {
-
-//                            新增 更新 对列过滤
-                        if (finalFilterColumns.contains(it) || finalFilterColumns.isEmpty() || (finalFilterColumns.get(0).equals("*") && finalFilterColumns.size() == 1)) {
-                            return o1.get(it);
-                        } else {
-                            return null;
-                        }
-                    }).toList());
+
+                Object joinConnectionDatasourceId = tableJoin.get("datasourceid");
+                String joinTableConnectionStr = connectionStr;
+                if (Objects.nonNull(joinConnectionDatasourceId)) {
+                    joinTableConnectionStr = DATABASE.queryConnectionStr(joinConnectionDatasourceId.toString());
                 }
-                if (Objects.nonNull(filterNames)) {
-                    Map<String, Object> o1 = ((Map<String, Object>) arg.getOrDefault("filter", arg));
-                    objects.addAll(filterNames.stream().map(o1::get).toList());
+
+                List<Map<String, Object>> targetDatas = DATABASE.query(joinTableConnectionStr, String.format("select * from %s", targetTable));
+
+                for (Map<String, Object> data : result) {
+                    targetDatas.stream()
+                            .filter(targetData -> Objects.equals(data.get(sourceJoinColumn), targetData.get(targetJoinColumn)))
+                            .findAny()
+                            .ifPresent(targetData -> {
+                                for (Map.Entry<String, String> stringStringEntry : showColumns.entrySet()) {
+                                    data.put(stringStringEntry.getValue(), targetData.get(stringStringEntry.getKey()));
+                                }
+                            });
                 }
-                values.add(objects.toArray());
             }
-            int[] ints = DATABASE.updateBatch(connectionStr, expression, values);
-            return UniReturnUtil.success(ints);
         }
+        return UniReturnUtil.success(result);
     }
 
+    /**
+     * 根据动态SQL执行方法。
+     * 通过传入的数据源ID、SQL表达式以及参数映射,执行相应的SQL查询,并返回查询结果的映射。
+     *
+     * @param datasourceId 数据源ID,用于指定执行SQL查询的数据源。
+     * @param expression   SQL表达式,可以是动态生成的SQL字符串。
+     * @param args         参数映射,包含SQL查询中需要的参数。
+     * @return 返回一个映射,包含查询结果的相关信息。
+     * @throws Exception 如果执行过程中出现错误,则抛出异常。
+     */
     public Map<String, Object> execByDynamicSql(String datasourceId, String expression, Map<String, Object> args) throws Exception {
         return execBySql(datasourceId, expression, args);
     }
 
+    /**
+     * 根据动态表名执行方法。
+     * 通过传入的数据源ID、表名以及参数映射,执行相应的SQL查询,并返回查询结果的映射。
+     *
+     * @param datasourceId 数据源ID,用于指定执行SQL查询的数据源。
+     * @param table        表名,可以是动态确定的表名。
+     * @param args         参数映射,包含SQL查询中需要的参数。
+     * @return 返回一个映射,包含查询结果的相关信息。
+     * @throws Exception 如果执行过程中出现错误,则抛出异常。
+     */
     public Map<String, Object> execByDynamicTableName(String datasourceId, String table, Map<String, Object> args) throws Exception {
         return execByTableName(datasourceId, table, args);
     }
 
-
+    /**
+     * 分页信息的记录类。
+     * 用于封装分页查询时的页码和每页大小。
+     */
     public record Pageable(Long page, Long pageSize) {
     }
 }

+ 41 - 5
src/main/java/com/scbfkj/uni/library/script/HttpScriptUtil.java

@@ -1,5 +1,6 @@
 package com.scbfkj.uni.library.script;
 
+import com.scbfkj.uni.exceptions.ConnectionNotFoundException;
 import com.scbfkj.uni.library.DataFormatUtil;
 import com.scbfkj.uni.process.DataBase;
 import com.scbfkj.uni.process.Web;
@@ -13,42 +14,77 @@ public class HttpScriptUtil {
 
     private static final DataBase DATA_BASE = new DataBase();
 
+    /**
+     * 根据数据源ID执行Web API调用。
+     *
+     * @param dataSourceId 数据源ID,用于查询对应的连接信息。
+     * @param data 包含调用Web API所需的各种参数的映射,如URL、请求头、请求体等。
+     * @return 返回一个包含Web API响应结果的映射。
+     * @throws Exception 如果执行过程中出现错误,则抛出异常。
+     */
     public static Map<String, Object> execByDataSourceId(String dataSourceId, Map<String, Object> data) throws Exception {
 
+            // 根据数据源ID查询连接配置信息
             Map<String, Object> connection = queryConnectionStr(dataSourceId);
+            // 如果data中包含url键,则将其值添加到connection中
             if(data.containsKey("url")){
                 connection.put("url",data.get("url"));
             }
+            // 如果data中包含headers键,则将其值添加到connection中
             if(data.containsKey("headers")){
                 connection.put("headers",data.get("headers"));
             }
+            // 如果data中包含body键,则将其值添加到connection中
             if(data.containsKey("body")){
                 connection.put("body",data.get("body"));
             }
-                connection.put("method",data.get("method"));
+            // 将data中的method键值对添加到connection中
+            connection.put("method",data.get("method"));
 
-        return new Web().execWebApi(connection.get("headers"), connection.getOrDefault("method", "post").toString(), connection.get("body"), DataFormatUtil.toString(connection.get("url")));
-    }
+            // 执行Web API调用,并返回结果
+            return new Web().execWebApi(connection.get("headers"), connection.getOrDefault("method", "post").toString(), connection.get("body"), DataFormatUtil.toString(connection.get("url")));
+        }
+    /**
+     * 执行Web API调用。
+     *
+     * @param header 用于API调用的请求头信息,可以为空。
+     * @param method API调用的方法类型,例如GET、POST等。
+     * @param defaultBody API调用的默认请求体内容,可以为空。
+     * @param url API调用的目标URL。
+     * @return 返回一个包含API响应信息的Map对象。
+     * @throws Exception 如果API调用过程中出现错误,则抛出异常。
+     */
     public static Map<String, Object> exec(Object header, String method, Object defaultBody, String url) throws Exception {
+        // 创建Web实例并调用其execWebApi方法执行API调用
         return new Web().execWebApi(header, method, defaultBody, url);
     }
 
 
+    /**
+     * 查询指定数据源ID的连接字符串信息。
+     *
+     * @param datasourceId 数据源ID,用于查询特定的数据源连接信息。
+     * @return 返回一个包含数据源连接信息的Map对象,包括URL("url")、HTTP头("headers")和HTTP正文("body")。
+     * @throws Exception 如果查询过程中发生错误,或者找不到指定的数据源ID,将抛出异常。
+     */
     private static Map<String, Object> queryConnectionStr(String datasourceId) throws Exception {
+        // 根据datasourceId查询datasource表中host, httpheaders, httpbody列
         List<Map<String, Object>> result = DATA_BASE.query(Config.getCenterConnectionStr(), """
                 select host,httpheaders,httpbody
                 from datasource
                 where datasourceid = ?""", datasourceId);
+        // 如果查询结果为空,抛出运行时异常
         if (result.isEmpty()) {
-            throw new RuntimeException("数据源错误:没有找到数据源");
+            throw new ConnectionNotFoundException("数据源错误:没有找到数据源");
         }
+        // 遍历查询结果,提取并返回第一个结果的host, httpheaders, httpbody到一个HashMap中
         return result.stream().findFirst().map(it -> {
             HashMap<String, Object> hashMap = new HashMap<>();
             hashMap.put("url", it.get("host"));
             hashMap.put("headers", it.get("httpheaders"));
             hashMap.put("body", it.get("httpbody"));
             return hashMap;
-        }).get();
+        }).orElse(new HashMap<>()); // 如果没有找到记录,返回一个空的HashMap
     }
 
 }

+ 125 - 58
src/main/java/com/scbfkj/uni/library/script/JavaScriptEngineUtil.java

@@ -19,126 +19,193 @@ import java.util.Map;
 import java.util.Objects;
 
 public class JavaScriptEngineUtil {
-
-    private final static KeyedObjectPool<String, JavaApply> javaRefPool = new GenericKeyedObjectPool<>(new BaseKeyedPooledObjectFactory<String, JavaApply>() {
-        @Override
-        public JavaApply create(String key) throws Exception {
-            JsonNode jsonNode = DataFormatUtil.toJsonNode(key);
-            JsonNode path = jsonNode.get("path");
-            JsonNode className = jsonNode.get("className");
-            JsonNode method = jsonNode.get("methodName");
-            ClassLoader classLoader = null;
-
-            if (Objects.nonNull(path) && !path.isNull()) {
-                String userPath = System.getProperty("user.dir");
-                File file = new File(userPath.concat(File.separator).concat("plugins").concat(File.separator).concat(path.asText()));
-                if (!file.exists()) {
-                    throw new RuntimeException("外部文件加载不存在:".concat(userPath).concat(File.separator).concat("plugins").concat(File.separator).concat(path.asText()));
-                }
-                URL url = file.toURI().toURL();
-                classLoader = new URLClassLoader(new URL[]{url}, Thread.currentThread().getContextClassLoader());
-            } else {
-                classLoader = Thread.currentThread().getContextClassLoader();
-            }
-
-            Class<?> classExample = classLoader.loadClass(className.asText()); //获取类实例
-            Method javaMethod = null;
-            Method closeMethod = null;
-            for (Method currentMethod : classExample.getMethods()) {//循环所有方法
-                String methodName = currentMethod.getName();
-                if (methodName.equals(method.asText())) {
-                    javaMethod = currentMethod;
-                } else if ("close".equals(methodName)) {
-                    closeMethod = currentMethod;
-                }
+/**
+ * 创建并管理Java应用执行实例的池子。这个池子keyed到具体的执行路径和类名上,允许复用Java方法的执行实例。
+ */
+private static final KeyedObjectPool<String, JavaApply> javaRefPool = new GenericKeyedObjectPool<>(new BaseKeyedPooledObjectFactory<String, JavaApply>() {
+
+    /**
+     * 根据提供的key创建一个新的JavaApply实例。
+     * @param key 包含执行路径、类名和方法名的JSON字符串。
+     * @return 一个初始化好的JavaApply实例,准备放入池中供调用。
+     * @throws Exception 如果过程中出现错误,比如类加载失败或方法找不到。
+     */
+    @Override
+    public JavaApply create(String key) throws Exception {
+        // 从key解析出路径、类名和方法名
+        JsonNode jsonNode = DataFormatUtil.toJsonNode(key);
+        JsonNode path = jsonNode.get("path");
+        JsonNode className = jsonNode.get("className");
+        JsonNode method = jsonNode.get("methodName");
+        ClassLoader classLoader = null;
+        // 根据提供的路径加载外部类
+        if (Objects.nonNull(path) && !path.isNull()) {
+            String userPath = System.getProperty("user.dir");
+            File file = new File(userPath.concat(File.separator).concat("plugins").concat(File.separator).concat(path.asText()));
+            // 检查文件是否存在
+            if (!file.exists()) {
+                throw new RuntimeException("外部文件加载不存在:".concat(userPath).concat(File.separator).concat("plugins").concat(File.separator).concat(path.asText()));
             }
-            Object classInstance = null;
-            if (javaMethod != null) {
-                int modifiers = javaMethod.getModifiers();
-                boolean aStatic = Modifier.isStatic(modifiers);
-                if (!aStatic) {
-//                    不是静态方法 需要实例化一个对象
-                    classInstance = classExample.getConstructor().newInstance();//类实例接口 无参数构造
-                }
-            }
-            return new JavaApply(classInstance, javaMethod, closeMethod);
+            URL url = file.toURI().toURL();
+            classLoader = new URLClassLoader(new URL[]{url}, Thread.currentThread().getContextClassLoader());
+        } else {
+            classLoader = Thread.currentThread().getContextClassLoader();
         }
-
-        @Override
-        public PooledObject<JavaApply> wrap(JavaApply value) {
-            return new DefaultPooledObject<>(value);
+        // 加载指定的类和方法
+        Class<?> classExample = classLoader.loadClass(className.asText());
+        Method javaMethod = null;
+        Method closeMethod = null;
+        for (Method currentMethod : classExample.getMethods()) {
+            String methodName = currentMethod.getName();
+            if (methodName.equals(method.asText())) {
+                javaMethod = currentMethod;
+            } else if ("close".equals(methodName)) {
+                closeMethod = currentMethod;
+            }
         }
 
-        @Override
-        public void destroyObject(String key, PooledObject<JavaApply> p) throws Exception {
-            JavaApply javaApply = p.getObject();
-            javaApply.invokeClose();
-
+        Object classInstance = null;
+        if (javaMethod != null) {
+            int modifiers = javaMethod.getModifiers();
+            boolean aStatic = Modifier.isStatic(modifiers);
+            // 如果方法非静态,则实例化类
+            if (!aStatic) {
+                classInstance = classExample.getConstructor().newInstance();
+            }
         }
-    });
 
+        // 返回包含类实例、方法和关闭方法的JavaApply对象
+        return new JavaApply(classInstance, javaMethod, closeMethod);
+    }
+    /**
+     * 将JavaApply实例包装成池能够管理的形式。
+     * @param value 需要被包装的JavaApply实例。
+     * @return 一个DefaultPooledObject,包含了一个JavaApply实例。
+     */
+    @Override
+    public PooledObject<JavaApply> wrap(JavaApply value) {
+        return new DefaultPooledObject<>(value);
+    }
+    /**
+     * 销毁从池中取出并使用后的JavaApply实例,调用其关闭方法。
+     * @param key 与该实例对应的key。
+     * @param p 包含了需要销毁的JavaApply实例的DefaultPooledObject。
+     * @throws Exception 如果在销毁过程中出现错误。
+     */
+    @Override
+    public void destroyObject(String key, PooledObject<JavaApply> p) throws Exception {
+        JavaApply javaApply = p.getObject();
+        javaApply.invokeClose();
+    }
+});
+
+    /**
+     * 根据提供的数据源、表达式和参数,调用相应的函数并返回结果。
+     * @param datasource 包含调用所需数据源信息的Map对象,其中必须包含方法名。
+     * @param expression 表达式,指定要调用的方法名。
+     * @param args 调用方法时传递的参数数组。
+     * @return 返回一个Map对象,包含调用结果或错误信息。
+     * @throws Exception 如果调用过程中发生异常,则抛出。
+     */
     public static Map<String, Object> invoke(Map<String, Object> datasource, String expression, Object... args) throws Exception {
+        // 将表达式设置为要调用的方法名
         datasource.put("methodName", expression);
+        // 通过数据源生成唯一的key
         String key = DataFormatUtil.toString(datasource);
 
         JavaApply javaApply = null;
         try {
+            // 从对象池中根据key借用JavaApply对象
             javaApply = javaRefPool.borrowObject(key);
+            // 调用借用的JavaApply对象的方法,并传入参数,返回结果
             return UniReturnUtil.success(javaApply.invokeApply(args));
         } catch (InvocationTargetException e) {
+            // 处理调用目标异常,返回失败结果
             return UniReturnUtil.fail(e.getTargetException());
         } catch (Exception e) {
+            // 处理其他异常,返回失败结果
             return UniReturnUtil.fail(e);
         } finally {
             if (Objects.nonNull(javaApply)) {
+                // 如果JavaApply对象非空,则归还到对象池
                 javaRefPool.returnObject(key, javaApply);
             }
         }
     }
-
+    /**
+     * JavaApply类用于封装对象实例、应用方法和关闭方法的调用。
+     */
     private static class JavaApply {
-        private Object instance;
-        private Method apply;
-        private Method close;
-
+        private Object instance; // 应用实例
+        private Method apply; // 应用的具体方法
+        private Method close; // 关闭资源的方法
+
+        /**
+         * 构造函数,初始化应用实例、应用方法和关闭方法。
+         *
+         * @param instance 应用的实例对象。
+         * @param apply 应用的具体方法。
+         * @param close 关闭资源的方法。
+         */
         public JavaApply(Object instance, Method apply, Method close) {
             this.instance = instance;
             this.apply = apply;
             this.close = close;
         }
 
+        // 获取应用实例的方法
         public Object getInstance() {
             return instance;
         }
 
+        // 设置应用实例的方法
         public void setInstance(Object instance) {
             this.instance = instance;
         }
 
+        // 获取应用方法的方法
         public Method getApply() {
             return apply;
         }
 
+        // 设置应用方法的方法
         public void setApply(Method apply) {
             this.apply = apply;
         }
 
+        // 获取关闭方法的方法
         public Method getClose() {
             return close;
         }
 
+        // 设置关闭方法的方法
         public void setClose(Method close) {
             this.close = close;
         }
 
+        /**
+         * 调用关闭方法。
+         *
+         * @throws InvocationTargetException 如果调用目标抛出异常。
+         * @throws IllegalAccessException 如果没有权限访问方法。
+         */
         public void invokeClose() throws InvocationTargetException, IllegalAccessException {
             if (Objects.nonNull(close)) {
                 close.invoke(instance);
             }
         }
 
+        /**
+         * 调用应用方法。
+         *
+         * @param args 方法调用的参数。
+         * @return 方法的返回值。
+         * @throws InvocationTargetException 如果调用目标抛出异常。
+         * @throws IllegalAccessException 如果没有权限访问方法。
+         */
         public Object invokeApply(Object... args) throws InvocationTargetException, IllegalAccessException {
             Class<?>[] parameterTypes = apply.getParameterTypes();
+            // 参数类型检查与转换
             for (int i = 0; i < parameterTypes.length; i++) {
                 Object arg = args[i];
                 if (!parameterTypes[i].isInstance(arg)) {
@@ -148,7 +215,7 @@ public class JavaScriptEngineUtil {
                 }
             }
             return apply.invoke(instance, args);
-
         }
     }
+
 }

+ 17 - 22
src/main/java/com/scbfkj/uni/library/script/JsScriptEngineUtil.java

@@ -1,8 +1,8 @@
 package com.scbfkj.uni.library.script;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
 import com.scbfkj.uni.library.DataFormatUtil;
 import com.scbfkj.uni.library.UniReturnUtil;
-import com.scbfkj.uni.system.Config;
 import org.graalvm.polyglot.Context;
 import org.graalvm.polyglot.Source;
 import org.graalvm.polyglot.Value;
@@ -10,7 +10,9 @@ import org.graalvm.polyglot.Value;
 import java.util.Map;
 
 public final class JsScriptEngineUtil {
+    private JsScriptEngineUtil() {
 
+    }
     private static final String TO_STRING_SCRIPT = """
             (value) => {
                 if (typeof value === 'string') return value
@@ -32,20 +34,9 @@ public final class JsScriptEngineUtil {
      * @return 执行结果,是一个包含执行结果的Map对象。
      * @throws Exception 如果执行过程中发生异常,则抛出Exception。
      */
-    public static Map<String, Object> eval(String script, Object args) throws Exception {
-
-        try {
-            // 尝试执行脚本并返回结果
-            return UniReturnUtil.success(exec(script, args));
-        } catch (Exception e) {
-            // 当处于调试模式时,输出脚本和参数信息以及异常栈跟踪
-            if (Config.isDebug()) {
-                System.out.println(script + "\n" + DataFormatUtil.toString(args));
-                e.printStackTrace();
-            }
-            // 重新抛出捕获到的异常
-            throw e;
-        }
+    public static Map<String, Object> eval(String script, Object args) throws JsonProcessingException {
+        // 尝试执行脚本并返回结果
+        return UniReturnUtil.success(exec(script, args));
     }
 
     /**
@@ -54,9 +45,8 @@ public final class JsScriptEngineUtil {
      * @param script 要执行的JavaScript脚本代码。
      * @param args   传递给脚本的参数,可以是任意类型。
      * @return 执行脚本后的结果,类型为Object,具体返回值取决于脚本的执行结果。
-     * @throws Exception 如果执行过程中发生错误,则抛出Exception。
      */
-    public static Object exec(String script, Object args) throws Exception {
+    public static Object exec(String script, Object args) throws JsonProcessingException {
 
         Source source = Source.create("js", script);
         try (Context context = Context.create("js")) {
@@ -80,12 +70,16 @@ public final class JsScriptEngineUtil {
 
     /**
      * 将 Value 对象转换为宿主对象。
+     * 这个方法主要用于将来自外部的 Value 类型数据转换为 Java 中的原生类型或者自定义的宿主对象。
+     * Value 对象可以代表多种类型的数据,包括基本类型、字符串、日期等。
      *
      * @param result Value对象,表示待转换的数据。
-     * @return 返回转换后的宿主对象。如果result是字符串,则返回对应的字符串对象;否则,将result转换为JSON节点对象。
-     * @throws Exception 如果转换过程中发生错误,则抛出异常。
+     * @return 返回转换后的宿主对象。如果result是字符串,则返回对应的字符串对象;
+     *         否则,将result转换为JSON节点对象。转换的具体规则根据 result 的类型决定。
+     * @throws Exception 如果转换过程中发生错误,则抛出异常。例如,当 result 为不支持的类型时。
      */
-    private static Object toHostObject(Value result) throws Exception {
+    private static Object toHostObject(Value result) throws JsonProcessingException {
+        // 判断result对象的类型,并进行相应的类型转换
         if (result.isNull()) {
             return null;
         }
@@ -108,11 +102,12 @@ public final class JsScriptEngineUtil {
             return result.asString();
         }
 
-        // 将result转换为字符串,并进一步转换为JSON节点对象
+        // 处理result为复杂类型(如JSON字符串)的情况,先转换为字符串再转换为JSON节点对象
         String string = jsToString(result);
         return DataFormatUtil.toJsonNode(string);
     }
 
+
     /**
      * 将JavaScript类型的值转换为字符串。
      *
@@ -120,7 +115,7 @@ public final class JsScriptEngineUtil {
      * @return 转换后的字符串。
      * @throws Exception 如果执行JavaScript脚本或转换过程中发生错误,则抛出异常。
      */
-    private static String jsToString(Value value) throws Exception {
+    private static String jsToString(Value value) {
         // 创建一个包含转换逻辑的JavaScript源码
         Source source = Source.create("js", TO_STRING_SCRIPT);
         try (Context context = Context.create("js")) {

+ 38 - 3
src/main/java/com/scbfkj/uni/library/script/KafkaScriptUtil.java

@@ -1,5 +1,6 @@
 package com.scbfkj.uni.library.script;
 
+import com.scbfkj.uni.exceptions.ConnectionNotFoundException;
 import com.scbfkj.uni.library.DataFormatUtil;
 import com.scbfkj.uni.process.DataBase;
 import com.scbfkj.uni.process.Kafka;
@@ -9,33 +10,67 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+/**
+ * Kafka脚本工具类,提供接收和发送Kafka消息的静态方法。
+ */
 public class KafkaScriptUtil {
 
+    // 数据库连接的单例
     private static final DataBase DATA_BASE = new DataBase();
 
+    /**
+     * 从指定数据源接收Kafka消息。
+     *
+     * @param dataSourceId 数据源ID,用于查询Kafka连接字符串
+     * @param topic Kafka主题
+     * @param groupId 消费组ID
+     * @param pollSize 每次轮询的最大消息数
+     * @return 包含接收到的消息的Map
+     * @throws Exception 查询数据库或接收消息时可能抛出的异常
+     */
     public static Map<String, Object> receptionMessage(String dataSourceId, String topic, String groupId,Long pollSize) throws Exception {
         return Kafka.receptionMessage(queryConnectionStr(dataSourceId,pollSize), topic, groupId);
     }
 
+    /**
+     * 向指定主题发送消息。
+     *
+     * @param dataSourceId 数据源ID,用于查询Kafka连接字符串
+     * @param topic Kafka主题
+     * @param datas 要发送的消息数据,可以是单个对象或对象列表
+     * @return 包含发送结果的Map
+     * @throws Exception 查询数据库或发送消息时可能抛出的异常
+     */
     public static Map<String, Object> sendMessage(String dataSourceId, String topic, Object datas) throws Exception {
         return Kafka.sendMessage(queryConnectionStr(dataSourceId, 1000L), topic, DataFormatUtil.toList(datas));
     }
 
-
+    /**
+     * 根据数据源ID查询Kafka的连接字符串。
+     *
+     * @param datasourceId 数据源ID
+     * @param pollSize 每次轮询的最大记录数,用于配置消费者
+     * @return Kafka的连接字符串
+     * @throws Exception 当查询不到对应的数据源时抛出ConnectionNotFoundException异常
+     */
     private static String queryConnectionStr(String datasourceId, Long pollSize) throws Exception {
+        // 从数据库查询数据源的Kafka主机地址
         List<Map<String, Object>> result = DATA_BASE.query(Config.getCenterConnectionStr(), """
                 select host
                 from datasource
                 where datasourceid = ?""", datasourceId);
+        // 如果查询结果为空,抛出连接未找到异常
         if (result.isEmpty()) {
-            throw new RuntimeException("数据源错误:没有找到数据源");
+            throw new ConnectionNotFoundException("数据源错误:没有找到数据源");
         }
+        // 配置Kafka连接参数并返回
         return result.stream().findFirst().map(it -> {
             HashMap<String, Object> hashMap = new HashMap<>();
             hashMap.put("bootstrap.servers", it.get("host"));
             hashMap.put("max.poll.records", pollSize);
             return hashMap;
-        }).map(DataFormatUtil::toString).get();
+        }).map(DataFormatUtil::toString).orElse(null);
     }
 
 }
+

+ 86 - 33
src/main/java/com/scbfkj/uni/process/ActiveMQ.java

@@ -12,19 +12,35 @@ import org.springframework.jms.core.JmsTemplate;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-
+/**
+ * ActiveMQ类用于提供与ActiveMQ消息队列交互的功能,包括接收消息和发送消息。
+ */
 public class ActiveMQ {
 
-
+    // JmsTemplate用于发送和接收消息
     private JmsTemplate jmsTemplate;
 
-    private final ObjectMapper mapper = new ObjectMapper();
-
+    // ObjectMapper用于对象与JSON字符串之间的转换
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    /**
+     * 从指定队列接收消息。
+     *
+     * @param host ActiveMQ服务器主机地址
+     * @param username 连接ActiveMQ的用户名
+     * @param password 连接ActiveMQ的密码
+     * @param queueName 需要接收消息的队列名称
+     * @param receiveTimeout 接收消息的超时时间
+     * @param pollSize 一次接收消息的最大数量
+     * @param retry 接收消息失败后的重试次数
+     * @return 返回接收到的消息列表
+     * @throws JMSException 如果接收消息过程中发生错误
+     */
     public List<String> receptionMessage(
             String host, String username, String password, String queueName, Long receiveTimeout, Long pollSize, Long retry) throws JMSException {
         JmsTemplate template = getJmsTemplate(host, username, password);
 
-
+        // 设置接收超时时间,并根据pollSize参数设置最大接收消息数量
         jmsTemplate.setReceiveTimeout(receiveTimeout);
         long maxSize = 100;
         if (pollSize > 0) {
@@ -33,99 +49,129 @@ public class ActiveMQ {
         int maxRetry = 0;
         List<String> result = new ArrayList<>();
 
-
+        // 循环接收消息,直到满足条件退出
         while (true) {
             try {
                 Message message = template.receive(queueName);
+                boolean found = false;
                 if (message == null) {
-                    break;
+                    found = true; // 没有消息时退出循环
                 } else if (message instanceof TextMessage msg) {
                     String text = msg.getText();
                     result.add(text);
                     if (result.size() >= maxSize) {
-                        break;
+                        found = true; // 接收到指定数量的消息后退出循环
                     }
                 }
+                if (found) {
+                    break;
+                }
             } catch (Exception e) {
                 maxRetry++;
                 if (maxRetry > retry) {
+                    // 重试次数超过设定值后退出,并返回已接收的消息
                     if (Config.isDebug()) {
                         e.printStackTrace();
                     }
                     if (jmsTemplate != null) {
                         jmsTemplate = null;
                     }
-
                     return result;
                 }
             }
         }
         return result;
-
-
     }
 
-
+    /**
+     * 向指定队列发送消息。
+     *
+     * @param host ActiveMQ服务器主机地址
+     * @param username 连接ActiveMQ的用户名
+     * @param password 连接ActiveMQ的密码
+     * @param queueName 需要发送消息的队列名称
+     * @param data 要发送的消息内容,支持发送Object数组或实现Iterable接口的对象
+     */
     public void sendMessage(
-            String host, String username, String password,  String queueName,
+            String host, String username, String password, String queueName,
             Object data
-    ) throws JMSException {
+    ) {
 
         JmsTemplate template = getJmsTemplate(host, username, password);
 
         try {
+            // 支持发送Object数组或实现Iterable接口的对象
             if (data instanceof Object[] datas) {
                 for (Object it : datas) {
-
                     execSend(template, it, queueName);
                 }
             } else if (data instanceof Iterable<?> datas) {
-
                 for (Object it : datas) {
-
                     execSend(template, it, queueName);
                 }
             } else {
                 execSend(template, data, queueName);
             }
-
         } catch (Exception e) {
+            // 发送失败的处理
             if (Config.isDebug()) {
                 e.printStackTrace();
             }
             if (jmsTemplate != null) {
                 jmsTemplate = null;
             }
-
         }
     }
 
-
+    /**
+     * 执行发送消息操作。
+     *
+     * @param template JmsTemplate实例,用于发送消息
+     * @param data 要发送的数据
+     * @param queueName 消息发送的目的地队列名称
+     * @throws IOException 在将数据转换为JSON字符串时发生错误
+     */
     private void execSend(
             JmsTemplate template,
             Object data,
             String queueName) throws IOException {
-        String message = mapper.writeValueAsString(data);
-
-        template.send(queueName, session -> session.createTextMessage(message));
+        String message = MAPPER.writeValueAsString(data); // 将数据转换为JSON字符串
+        template.send(queueName, session -> session.createTextMessage(message)); // 发送消息
     }
 
-
+    /**
+     * 创建ActiveMQ连接工厂。
+     *
+     * @param host ActiveMQ服务器主机地址
+     * @param username 连接ActiveMQ的用户名
+     * @param password 连接ActiveMQ的密码
+     * @return 返回创建的ConnectionFactory对象
+     */
     private jakarta.jms.ConnectionFactory createConnectionFactory(String host, String username, String password) {
-        ActiveMQJMSConnectionFactory connectionFactory = new ActiveMQJMSConnectionFactory(host, username, password);
-
-        return connectionFactory;
+        return new ActiveMQJMSConnectionFactory(host, username, password);
     }
 
-
+    /**
+     * 创建CachingConnectionFactory,用于缓存连接。
+     *
+     * @param factory ConnectionFactory对象
+     * @return 返回创建的CachingConnectionFactory对象
+     */
     private CachingConnectionFactory createCachingConnectionFactory(jakarta.jms.ConnectionFactory factory) {
         CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
         cachingConnectionFactory.setTargetConnectionFactory(factory);
         return cachingConnectionFactory;
     }
 
-
-    private JmsTemplate getJmsTemplate(String host, String username, String password) throws JMSException {
+    /**
+     * 获取JmsTemplate实例,如果不存在则创建新的实例。
+     *
+     * @param host ActiveMQ服务器主机地址
+     * @param username 连接ActiveMQ的用户名
+     * @param password 连接ActiveMQ的密码
+     * @return 返回JmsTemplate实例
+     */
+    private JmsTemplate getJmsTemplate(String host, String username, String password) {
         if (jmsTemplate == null) {
             jakarta.jms.ConnectionFactory connectionFactory = createConnectionFactory(host, username, password);
             CachingConnectionFactory cachingConnectionFactory = createCachingConnectionFactory(connectionFactory);
@@ -134,9 +180,16 @@ public class ActiveMQ {
         return jmsTemplate;
     }
 
+    /**
+     * 创建JmsTemplate实例。
+     *
+     * @param factory ConnectionFactory对象
+     * @return 返回创建的JmsTemplate实例
+     */
     private JmsTemplate createJmsTemplate(CachingConnectionFactory factory) {
-        JmsTemplate jmsTemplate = new JmsTemplate();
-        jmsTemplate.setConnectionFactory(factory);
-        return jmsTemplate;
+        JmsTemplate template = new JmsTemplate();
+        template.setConnectionFactory(factory);
+        return template;
     }
 }
+

File diff suppressed because it is too large
+ 515 - 195
src/main/java/com/scbfkj/uni/process/DataBase.java


+ 305 - 150
src/main/java/com/scbfkj/uni/process/Elasticsearch.java

@@ -1,10 +1,11 @@
 package com.scbfkj.uni.process;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
+
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.JsonNodeFactory;
 import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.scbfkj.uni.exceptions.ConnectionNotFoundException;
 import com.scbfkj.uni.library.DataFormatUtil;
 import com.scbfkj.uni.library.UniReturnUtil;
 import com.scbfkj.uni.system.Config;
@@ -19,6 +20,8 @@ import org.elasticsearch.client.Request;
 import org.elasticsearch.client.Response;
 import org.elasticsearch.client.RestClient;
 import org.elasticsearch.client.RestClientBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.http.HttpStatus;
 
 import java.io.IOException;
@@ -26,195 +29,333 @@ import java.util.*;
 
 public class Elasticsearch {
 
-    private static final Map<String, RestClient> restClientMap = new HashMap<>();
+    /**
+     * 日志记录器,用于记录Elasticsearch操作的日志。
+     */
+    private static Logger logger = LoggerFactory.getLogger(Elasticsearch.class);
+
+    /**
+     * Elasticsearch类的私有构造方法,防止实例化。
+     */
+    private Elasticsearch() {
+    }
+
+    /**
+     * 用于存储RestClient实例的映射,键为数据源ID。
+     */
+    private static final Map<String, RestClient> REST_CLIENT_MAP = new HashMap<>();
 
+    /**
+     * 数据库操作的单例对象,用于与数据库交互。
+     */
     private static final DataBase DATA_BASE = new DataBase();
-    public static Map<String ,Object> execByDataSourceId(String dataSourceId,String indexName, String event, List<String> datas) throws Exception {
-        return exec(queryConnectionStr(dataSourceId),indexName,event,datas);
+
+    /**
+     * 根据数据源ID执行操作,并返回结果。
+     * @param dataSourceId 数据源ID,用于确定使用哪个数据源。
+     * @param indexName Elasticsearch索引名称。
+     * @param event 事件名称,标识执行的具体操作。
+     * @param datas 执行操作所需要的数据列表。
+     * @return 返回操作的结果,为一个Map对象。
+     * @throws Exception 如果执行过程中出现错误,则抛出异常。
+     */
+    public static Map<String, Object> execByDataSourceId(String dataSourceId, String indexName, String event, List<String> datas) throws Exception {
+        return exec(queryConnectionStr(dataSourceId), indexName, event, datas);
     }
 
+    /**
+     * 用户名和密码,用于数据库或Elasticsearch的认证。
+     */
+    private static final String USERNAME = "username";
+    private static final String PASSWORD = "password";
+
+    /**
+     * 执行与特定索引相关的HTTP操作。
+     *
+     * @param connection 连接配置信息,用于创建RestClient实例。
+     * @param indexName 索引名称,指定操作的目标索引。如果为空,则默认操作根索引。
+     * @param event 事件类型,决定了执行的HTTP方法(如CREATE、SEARCH、UPDATE等)。
+     * @param datas 数据列表,用于操作的数据集合。
+     * @return 返回一个Map,包含操作的结果。成功时,包含执行结果;失败时,包含错误信息。
+     */
     public static Map<String, Object> exec(String connection, String indexName, String event, List<String> datas) {
+        // 检查数据列表是否为空
         if (Objects.isNull(datas) || datas.isEmpty()) {
             return UniReturnUtil.fail("数据为空");
         }
 
+        // 创建RestClient实例
         RestClient restClient = create(connection);
+        // 尝试从连接配置中解析参数
         Map<?, ?> map = DataFormatUtil.toMap(connection);
+        // 默认操作端点为根路径
         String endpoint = indexName;
         if (Objects.isNull(endpoint)) {
             endpoint = "/";
         }
-        Object method = "GET";
+
+        // 根据事件类型确定HTTP方法
+        Object method;
         switch (event.toUpperCase()) {
-            case "CREATE" -> {
-                method = "POST";
-            }
-            case "UPDATE" -> {
-                method = "PUT";
-            }
-            case "DELETE" -> {
-                method = "DELETE";
-            }
-            case "SEARCH" -> {
-                method = "POST";
-            }
-            case "GET" -> {
-                method = "GET";
-            }
+            case "CREATE", "SEARCH" -> method = "POST";
+            case "UPDATE" -> method = "PUT";
+            case "DELETE", "GET" -> method = event.toUpperCase();
+            default -> throw new IllegalStateException("Unexpected value: " + event.toUpperCase());
         }
 
+        // 收集参数
         Map<String, String> parametersMap = new HashMap<>();
-        Object parameters = map.get("parameters");
+        Object parameters = null;
+        if (map != null) {
+            parameters = map.get("parameters");
+        }
         if (Objects.nonNull(parameters)) {
             parametersMap.putAll((Map<String, String>) parameters);
         }
 
+        // 执行HTTP操作,并收集结果
         Object finalMethod = method;
         String finalEndpoint = endpoint;
         List<Object> results = new ArrayList<>();
         try {
-            for (String data : datas) {
-                String uri = finalEndpoint;
-                Object result = null;
-                Request request = null;
-                switch (event.toUpperCase()) {
-                    case "CREATE" -> {
-                        uri += "/_doc/";
-                        request = new Request(finalMethod.toString(), uri);
-                        request.addParameters(parametersMap);
-                        request.setJsonEntity(data);
-                        Response response = restClient.performRequest(request);
-                        if (response != null && HttpStatus.CREATED.value() == response.getStatusLine().getStatusCode()) {
-                            String responseBody = null;
-                            try {
-                                responseBody = EntityUtils.toString(response.getEntity());
-                            } catch (IOException e) {
-                                throw new RuntimeException(e);
-                            }
-                            result = Collections.singletonList(responseBody);
-                        } else {
-                            result = Collections.singletonList(false);
-                        }
-                    }
-                    case "UPDATE" -> {
-                        ObjectNode jsonNodes = DataFormatUtil.stringToObjectNode(data);
-                        JsonNode id = jsonNodes.get("_id");
-                        uri += "/_doc/" + id.asText();
-                        request = new Request(finalMethod.toString(), uri);
-                        request.addParameters(parametersMap);
-                        request.setJsonEntity(DataFormatUtil.toString(jsonNodes.get("data")));
-                        Response response = restClient.performRequest(request);
-                        if (response != null && HttpStatus.OK.value() == response.getStatusLine().getStatusCode()) {
-                            String responseBody = null;
-                            try {
-                                responseBody = EntityUtils.toString(response.getEntity());
-                            } catch (IOException e) {
-                                throw new RuntimeException(e);
-                            }
-                            result = Collections.singletonList(responseBody);
-                        } else {
-                            result = Collections.singletonList(false);
-                        }
-
-                    }
-                    case "DELETE" -> {
-                        uri += "/_doc/" + data;
-                        request = new Request(finalMethod.toString(), uri);
-                        request.addParameters(parametersMap);
-                        Response response = restClient.performRequest(request);
-                        if (response != null && HttpStatus.OK.value() == response.getStatusLine().getStatusCode()) {
-                            String responseBody = null;
-                            try {
-                                responseBody = EntityUtils.toString(response.getEntity());
-                            } catch (IOException e) {
-                                throw new RuntimeException(e);
-                            }
-                            result = Collections.singletonList(responseBody);
-                        } else {
-                            result = Collections.singletonList(false);
-                        }
-                    }
-                    case "GET" -> {
-                        uri += "/_doc/" + data;
-                        request = new Request(finalMethod.toString(), uri);
-                        request.addParameters(parametersMap);
-                        Response response = restClient.performRequest(request);
-                        if (response != null && HttpStatus.OK.value() == response.getStatusLine().getStatusCode()) {
-                            String responseBody = null;
-                            try {
-                                responseBody = EntityUtils.toString(response.getEntity());
-                            } catch (IOException e) {
-                                throw new RuntimeException(e);
-                            }
-                            result = Collections.singletonList(responseBody);
-                        } else {
-                            result = Collections.singletonList(false);
-                        }
-                    }
-                    case "SEARCH" -> {
-                        uri += "/_search";
-                        request = new Request(finalMethod.toString(), uri);
-                        request.addParameters(parametersMap);
-
-                        ObjectNode jsonNodes = DataFormatUtil.stringToObjectNode(data);
-                        request.setJsonEntity(jsonNodes.toString());
-                        Response response = restClient.performRequest(request);
-                        if (response != null && HttpStatus.OK.value() == response.getStatusLine().getStatusCode()) {
-                            String responseBody = null;
-                            try {
-                                responseBody = EntityUtils.toString(response.getEntity());
-                            } catch (IOException e) {
-                                throw new RuntimeException(e);
-                            }
-                            ObjectNode jsonObject = null;
-                            try {
-                                jsonObject = DataFormatUtil.stringToObjectNode(responseBody);
-                            } catch (JsonProcessingException e) {
-                                throw new RuntimeException(e);
-                            }
-                            ObjectNode jsonObject1 = (ObjectNode) (jsonObject.get("hits")).get("total");
-                            if (jsonObject1.get("value") != null) {
-                                Integer total = jsonObject1.get("value").asInt();
-                                System.out.println("总记录数:" + total);
-                            }
-                            //处理返回结果
-                            ArrayNode jsonArray = (ArrayNode) (jsonObject.get("hits")).get("hits");
-
-                            ArrayNode objects = new ArrayNode(JsonNodeFactory.instance);
-                            for (JsonNode e : jsonArray) {
-                                ObjectNode source = (ObjectNode) e.get("_source");
-                                objects.add(source);
-                            }
-                            result = objects;
-                        }
-
-                    }
-                }
-
-
-                results.add(result);
-            }
+            execHttp(event, datas, finalEndpoint, finalMethod, parametersMap, restClient, results);
         } catch (Exception e) {
             return UniReturnUtil.fail(e);
         }
+        // 返回操作结果
         return UniReturnUtil.success(results);
     }
 
+    /**
+     * 执行HTTP操作,根据提供的事件类型(如创建、更新、删除、获取或搜索)对数据进行处理。
+     *
+     * @param event 事件类型,指示执行哪种HTTP操作。
+     * @param datas 需要处理的数据列表。
+     * @param finalEndpoint 目标端点URL。
+     * @param finalMethod 要执行的方法类型(如GET、POST等)。
+     * @param parametersMap 请求参数的映射。
+     * @param restClient 用于执行HTTP请求的REST客户端实例。
+     * @param results 存储操作结果的列表。
+     * @throws IOException 如果执行HTTP请求时发生IO错误。
+     */
+    private static void execHttp(String event, List<String> datas, String finalEndpoint, Object finalMethod, Map<String, String> parametersMap, RestClient restClient, List<Object> results) throws IOException {
+        // 遍历数据列表,对每条数据执行指定的HTTP操作
+        for (String data : datas) {
+            Object result = null;
+            final String doc = "/_doc/";
+            // 根据事件类型执行相应的HTTP操作
+            switch (event.toUpperCase()) {
+                case "CREATE" -> result = create(finalMethod, parametersMap, restClient, data, finalEndpoint, doc);
+                case "UPDATE" -> result = update(finalMethod, parametersMap, restClient, data, finalEndpoint, doc);
+                case "DELETE", "GET" -> result = execMethod(restClient, parametersMap, finalMethod, data, finalEndpoint);
+                case "SEARCH" -> result = search(finalMethod, parametersMap, restClient, data, finalEndpoint, result);
+                default -> throw new IllegalStateException("Unexpected value: " + event.toUpperCase());
+            }
+            // 将操作结果添加到结果列表中
+            results.add(result);
+        }
+    }
+
+
+    /**
+     * 对给定的URI执行搜索操作,并返回搜索结果。
+     *
+     * @param finalMethod 最终使用的HTTP方法(如GET、POST等)
+     * @param parametersMap 搜索参数的映射
+     * @param restClient 用于执行REST请求的客户端
+     * @param data 包含搜索查询的JSON数据
+     * @param uri 搜索操作的目标URI
+     * @param result 用于存储搜索结果的容器,函数执行后会更新此参数
+     * @return 返回处理后的搜索结果
+     * @throws IOException 如果执行REST请求或处理响应时发生IO错误
+     */
+    private static Object search(Object finalMethod, Map<String, String> parametersMap, RestClient restClient, String data, String uri, Object result) throws IOException {
+        // 创建请求并设置URI和方法
+        Request request;
+        uri += "/_search";
+        request = new Request(finalMethod.toString(), uri);
+
+        // 添加参数到请求
+        request.addParameters(parametersMap);
+
+        // 将JSON字符串转换为ObjectNode,并设置为请求的实体
+        ObjectNode jsonNodes = DataFormatUtil.stringToObjectNode(data);
+        request.setJsonEntity(jsonNodes.toString());
+
+        // 执行搜索请求
+        Response response = restClient.performRequest(request);
+
+        // 检查响应状态,若成功则处理响应体
+        if (response != null && HttpStatus.OK.value() == response.getStatusLine().getStatusCode()) {
+            String responseBody = EntityUtils.toString(response.getEntity());
+
+            // 将响应体转换为JSON ObjectNode
+            ObjectNode jsonObject = DataFormatUtil.stringToObjectNode(responseBody);
+
+            // 提取并处理搜索结果的总数
+            ObjectNode jsonObject1 = (ObjectNode) (jsonObject.get("hits")).get("total");
+            if (jsonObject1.get("value") != null) {
+                int total = jsonObject1.get("value").asInt();
+                logger.info("总记录数:{}", total);
+            }
+
+            // 处理返回的搜索结果文档
+            ArrayNode jsonArray = (ArrayNode) (jsonObject.get("hits")).get("hits");
+            ArrayNode objects = new ArrayNode(JsonNodeFactory.instance);
+            for (JsonNode e : jsonArray) {
+                ObjectNode source = (ObjectNode) e.get("_source");
+                objects.add(source);
+            }
+            result = objects; // 更新结果参数
+        }
+        return result;
+    }
+
+
+    /**
+     * 更新操作,通过REST客户端向指定URI发送请求来更新数据。
+     *
+     * @param finalMethod HTTP方法类型,例如GET、POST、PUT等,用于构造请求。
+     * @param parametersMap 请求参数的映射,将作为请求的一部分。
+     * @param restClient REST客户端实例,用于发送请求。
+     * @param data 要更新的数据,格式为JSON字符串。
+     * @param uri 更新操作的目标URI。
+     * @param doc 文档标识符,用于构建完整的请求URI。
+     * @return 返回执行请求后的响应对象。
+     * @throws IOException 如果发送请求过程中发生IO错误。
+     */
+    private static Object update(Object finalMethod, Map<String, String> parametersMap, RestClient restClient, String data, String uri, String doc) throws IOException {
+        // 根据提供的JSON字符串解析出ObjectNode
+        Request request;
+        ObjectNode jsonNodes = DataFormatUtil.stringToObjectNode(data);
+        // 获取并构建最终请求的URI
+        JsonNode id = jsonNodes.get("_id");
+        uri += doc + id.asText();
+        // 创建请求对象,并设置方法类型、URI和参数
+        request = new Request(finalMethod.toString(), uri);
+        request.addParameters(parametersMap);
+        // 设置请求的JSON实体
+        request.setJsonEntity(DataFormatUtil.toString(jsonNodes.get("data")));
+        // 发送请求并返回响应对象
+        return getObject(restClient, request);
+    }
+
+
+    /**
+     * 通过REST客户端发送请求,并获取响应结果。
+     *
+     * @param restClient 用于执行请求的REST客户端实例。
+     * @param request 要发送的HTTP请求。
+     * @return 返回一个包含响应结果的对象。如果请求成功(状态码为200),则返回一个包含响应体字符串的列表;如果请求失败,则返回一个包含false的列表。
+     * @throws IOException 如果发生I/O错误。
+     */
+    private static Object getObject(RestClient restClient, Request request) throws IOException {
+        Object result;
+        // 执行请求并获取响应
+        Response response = restClient.performRequest(request);
+        if (response != null && HttpStatus.OK.value() == response.getStatusLine().getStatusCode()) {
+            // 请求成功,将响应体转换为字符串并返回
+            String responseBody = EntityUtils.toString(response.getEntity());
+            result = Collections.singletonList(responseBody);
+        } else {
+            // 请求失败,返回false表示请求未成功
+            result = Collections.singletonList(false);
+        }
+        return result;
+    }
+
 
+    /**
+     * 新增资源的方法。
+     * 通过向指定URI发送HTTP请求来创建一个新的资源。请求可以包含参数和请求体数据。
+     * 如果创建成功,返回创建的资源的表示;如果创建失败,返回一个错误标志。
+     *
+     * @param finalMethod HTTP请求方法,例如GET、POST等。
+     * @param parametersMap 请求参数的键值对。
+     * @param restClient 用于执行HTTP请求的REST客户端。
+     * @param data 请求体数据,通常为JSON格式。
+     * @param uri 要发送请求的URI。
+     * @param doc 附加到URI的文档路径。
+     * @return 返回一个包含创建结果的对象。如果创建成功,返回包含资源表示的列表;如果失败,返回包含false的列表。
+     * @throws IOException 如果发生I/O错误。
+     */
+    private static Object create(Object finalMethod, Map<String, String> parametersMap, RestClient restClient, String data, String uri, String doc) throws IOException {
+        Request request;
+        Object result;
+        // 构造完整的请求URI
+        uri += doc;
+        // 创建请求对象并设置方法、URI和参数
+        request = new Request(finalMethod.toString(), uri);
+        request.addParameters(parametersMap);
+        request.setJsonEntity(data);
+        // 执行请求并获取响应
+        Response response = restClient.performRequest(request);
+        if (response != null && HttpStatus.CREATED.value() == response.getStatusLine().getStatusCode()) {
+            // 如果响应状态为创建成功,则提取响应体内容作为结果
+            String responseBody = EntityUtils.toString(response.getEntity());
+            result = Collections.singletonList(responseBody);
+        } else {
+            // 如果创建失败,返回false标志
+            result = Collections.singletonList(false);
+        }
+        return result;
+    }
+
+
+    /**
+     * 执行REST客户端的方法。
+     *
+     * @param restClient RestClient实例,用于执行HTTP请求。
+     * @param parametersMap 包含请求参数的映射。
+     * @param finalMethod 将要执行的方法名称。
+     * @param data 方法执行中使用的数据标识符。
+     * @param uri 请求的基础URI。
+     * @return 执行请求后的响应对象。
+     * @throws IOException 如果发生I/O错误。
+     */
+    private static Object execMethod(RestClient restClient, Map<String, String> parametersMap, Object finalMethod, String data, String uri) throws IOException {
+        Request request;
+        // 构建完整的URI
+        uri += "/_doc/" + data;
+        // 创建请求对象并设置方法名称和URI
+        request = new Request(finalMethod.toString(), uri);
+        // 添加请求参数
+        request.addParameters(parametersMap);
+        // 执行请求并返回响应对象
+        return getObject(restClient, request);
+    }
+
+
+    /**
+     * 创建RestClient实例。
+     * 该方法根据提供的connection字符串来创建或获取一个RestClient实例。如果已经存在对应的RestClient实例,则直接返回;
+     * 否则,根据connection字符串解析配置,并构建新的RestClient实例。
+     *
+     * @param connection 用于配置RestClient的字符串,可以包含主机地址、用户名、密码或令牌信息。
+     * @return 返回配置好的RestClient实例。
+     */
     private static RestClient create(String connection) {
-        RestClient restClient = restClientMap.get(connection);
+        // 尝试从缓存中获取RestClient实例
+        RestClient restClient = REST_CLIENT_MAP.get(connection);
         if (Objects.nonNull(restClient)) {
             return restClient;
         }
+
+        // 解析connection字符串为Map格式
         Map<?, ?> map = DataFormatUtil.toMap(connection);
 
+        // 从map中提取host信息,并转换为HttpHost数组
         List<String> hosts = (List<String>) map.get("host");
         HttpHost[] httpHosts = hosts.stream().map(HttpHost::create).toArray(HttpHost[]::new);
+        // 使用HttpHost数组构建RestClientBuilder
         RestClientBuilder builder = RestClient.builder(httpHosts);
-        Object username = map.get("username");
-        Object password = map.get("password");
+
+        // 配置认证信息,支持使用用户名和密码或令牌进行认证
+        Object username = map.get(USERNAME);
+        Object password = map.get(PASSWORD);
         Object token = map.get("token");
         if (Objects.nonNull(username) && Objects.nonNull(password)) {
+            // 配置基于用户名和密码的认证
             builder.setHttpClientConfigCallback(httpClientBuilder -> {
                 BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
                 credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username.toString(), password.toString()));
@@ -223,28 +364,42 @@ public class Elasticsearch {
             });
 
         } else if (Objects.nonNull(token)) {
+            // 配置基于令牌的认证
             builder.setDefaultHeaders(new Header[]{new BasicHeader("AuthorizationScript", "Bearer " + token)});
         }
+        // 构建RestClient实例,并加入到缓存中
         restClient = builder.build();
-        restClientMap.put(connection, restClient);
+        REST_CLIENT_MAP.put(connection, restClient);
         return restClient;
     }
 
 
+    /**
+     * 获取指定数据源ID的连接字符串。
+     * @param datasourceId 数据源ID,用于查询数据库中对应的连接信息。
+     * @return 返回一个字符串形式的连接信息,包含主机地址、用户名和密码。
+     * @throws Exception 如果查询过程中发生错误,或者未找到对应的数据源ID,将抛出异常。
+     */
     private static String queryConnectionStr(String datasourceId) throws Exception {
+        // 从数据库中查询指定数据源ID的主机地址
         List<Map<String, Object>> result = DATA_BASE.query(Config.getCenterConnectionStr(), """
                 select host
                 from datasource
                 where datasourceid = ?""", datasourceId);
+
+        // 如果查询结果为空,抛出连接未找到的异常
         if (result.isEmpty()) {
-            throw new RuntimeException("数据源错误:没有找到数据源");
+            throw new ConnectionNotFoundException("数据源错误:没有找到数据源");
         }
+
+        // 处理查询结果,构建并返回连接字符串
         return result.stream().findFirst().map(it -> {
             HashMap<String, Object> hashMap = new HashMap<>();
             hashMap.put("host", it.get("host"));
-            hashMap.put("username", it.get("username"));
-            hashMap.put("password", it.get("password"));
+            hashMap.put(USERNAME, it.get(USERNAME)); // 这里假设USERNAME是一个已定义的常量
+            hashMap.put(PASSWORD, it.get(PASSWORD)); // 同上,假设PASSWORD是一个已定义的常量
             return hashMap;
-        }).map(DataFormatUtil::toString).get();
+        }).map(DataFormatUtil::toString).orElse(null);
     }
+
 }

+ 37 - 55
src/main/java/com/scbfkj/uni/process/Email.java

@@ -1,29 +1,45 @@
 package com.scbfkj.uni.process;
 
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import javax.mail.*;
-import javax.mail.internet.AddressException;
 import javax.mail.internet.InternetAddress;
 import javax.mail.internet.MimeMessage;
 import java.util.Map;
 import java.util.Properties;
-
+/**
+ * Email类用于发送电子邮件。
+ * 该类不可实例化,提供了一个静态方法sendEmail用于发送邮件。
+ */
 public class Email {
+    // 私有构造方法防止实例化
+    private Email() {
+    }
 
-    public static void sendEmail(Map properties, String username, String password, String to, String subject, String body) throws MessagingException {
-        // 设置发件人邮箱和密码
+    // 日志记录器,用于记录邮件发送状态
+    private static final Logger logger = LoggerFactory.getLogger(Email.class);
 
+    /**
+     * 发送电子邮件的方法。
+     *
+     * @param properties 邮件服务器的属性,包含必要的配置信息。
+     * @param username 发件人的邮箱账号。
+     * @param password 发件人的邮箱密码。
+     * @param to 收件人的邮箱地址。
+     * @param subject 邮件主题。
+     * @param body 邮件正文。
+     * @throws MessagingException 如果邮件发送过程中出现错误,则抛出此异常。
+     */
+    public static void sendEmail(Map<String, Object> properties, String username, String password, String to, String subject, String body) throws MessagingException {
+        // 设置发件人邮箱和密码
 
-        // 设置邮件服务器属性
+        // 初始化邮件服务器属性并覆盖传入的properties
         Properties props = new Properties();
         props.putAll(properties);
-//        props.put("mail.smtp.auth", "true");
-//        props.put("mail.smtp.starttls.enable", "true");
-//        props.put("mail.smtp.host", "smtp.gmail.com");
-//        props.put("mail.smtp.port", "587");
 
-        // 创建会话
+        // 创建SMTP会话,使用提供的邮箱账号和密码进行身份验证
         Session session = Session.getInstance(props, new Authenticator() {
             @Override
             protected PasswordAuthentication getPasswordAuthentication() {
@@ -31,52 +47,18 @@ public class Email {
             }
         });
 
-            // 创建邮件消息
-            Message message = new MimeMessage(session);
-            message.setFrom(new InternetAddress(username));
-            message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to));
-            message.setSubject(subject);
-            message.setText(body);
-
-            // 发送邮件
-            Transport.send(message);
-
-            System.out.println("邮件发送成功");
+        // 创建邮件消息,设置发件人、收件人、主题和正文
+        Message message = new MimeMessage(session);
+        message.setFrom(new InternetAddress(username));
+        message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to));
+        message.setSubject(subject);
+        message.setText(body);
 
+        // 发送邮件
+        Transport.send(message);
 
+        // 记录邮件发送成功的日志
+        logger.info("邮件发送成功");
     }
-//    public static void sendEmailByDataSourceId(String dataSourceId, String to, String subject, String body) throws MessagingException {
-//        // 设置发件人邮箱和密码
-//
-//
-//        // 设置邮件服务器属性
-//        Properties props = new Properties();
-//        props.putAll(properties);
-////        props.put("mail.smtp.auth", "true");
-////        props.put("mail.smtp.starttls.enable", "true");
-////        props.put("mail.smtp.host", "smtp.gmail.com");
-////        props.put("mail.smtp.port", "587");
-//
-//        // 创建会话
-//        Session session = Session.getInstance(props, new Authenticator() {
-//            @Override
-//            protected PasswordAuthentication getPasswordAuthentication() {
-//                return new PasswordAuthentication(username, password);
-//            }
-//        });
-//
-//            // 创建邮件消息
-//            Message message = new MimeMessage(session);
-//            message.setFrom(new InternetAddress(username));
-//            message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to));
-//            message.setSubject(subject);
-//            message.setText(body);
-//
-//            // 发送邮件
-//            Transport.send(message);
-//
-//            System.out.println("邮件发送成功");
-//
-//
-//    }
 }
+

+ 69 - 49
src/main/java/com/scbfkj/uni/process/FTP.java

@@ -1,16 +1,20 @@
 package com.scbfkj.uni.process;
 
+import com.scbfkj.uni.exceptions.ConnectionNotFoundException;
 import com.scbfkj.uni.library.DataFormatUtil;
 import com.scbfkj.uni.library.UniReturnUtil;
 import com.scbfkj.uni.system.Config;
 import org.apache.commons.net.ftp.FTPClient;
 import org.apache.commons.net.ftp.FTPFile;
 import org.apache.commons.net.ftp.FTPReply;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.util.StringUtils;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
+import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.time.Duration;
@@ -19,119 +23,124 @@ import java.util.zip.GZIPInputStream;
 
 import static org.apache.commons.net.ftp.FTP.BINARY_FILE_TYPE;
 
+/**
+ * ftp操作类
+ *
+/*
+ * FTP类用于处理FTP文件下载。
+ */
 public class FTP {
     private static final int BUFFER_SIZE = 4096;
     private static final DataBase DATA_BASE = new DataBase();
 
-    public Map<String, Object> updateByDataSourceId(String datasourceId,String targetPath, String sourcePath) throws Exception {
-        String config = queryConnectionStr(datasourceId);
-        return update(config,targetPath,sourcePath);
-    }
-    public Map<String, Object> update(String connectionConfig, String targetPath, String sourcePath) {
-        return null;
-    }
-
+    private static final Logger logger = LoggerFactory.getLogger(FTP.class);
 
     /**
-     * 设置ftp客户端参数并创建ftp客户端
+     * 创建FTP客户端并设置相关参数。
      *
-     * @param config ftp连接配置信息
-     * @return ftp客户端
+     * @param config 包含FTP连接信息的配置映射,如host、username、password等。
+     * @return 已连接并配置好的FTP客户端实例。
+     * @throws IOException 如果连接失败或发生IO错误。
      */
-    private FTPClient createFtpClient(Map<String, Object> config) throws Exception {
+    private FTPClient createFtpClient(Map<String, Object> config) throws IOException {
         FTPClient ftp = new FTPClient();
         int port = 21;
         String host = Objects.toString(config.get("host"));
-        if(host.contains(":")){
+        // 解析主机和端口
+        if (host.contains(":")) {
             String[] split = host.split(":");
             port = Integer.parseInt(split[1]);
             host = split[0];
         }
         ftp.connect(host, port);
-        //common-net的ftpclient默认是使用ASCII_FILE_TYPE,文件会经过ASCII编码转换,所以可能会造成文件损坏
-        ftp.login(Objects.toString(config.get("username")), Objects.toString(config.get("password")));//登录
+        // 登录FTP服务器
+        ftp.login(Objects.toString(config.get("username")), Objects.toString(config.get("password")));
+        // 设置连接超时时间
         String timeOutStr = "timeOut";
-        //120秒
         int timeOut = Objects.nonNull(config.get(timeOutStr)) ? Integer.parseInt(Objects.toString(config.get(timeOutStr))) : (1000 * 120);
         ftp.setConnectTimeout(timeOut);
         ftp.setDataTimeout(Duration.ofSeconds(timeOut));
-        //每次读取文件流时缓存数组的大小
+        // 设置缓冲区大小和其他参数
         ftp.setBufferSize(1024 * 1024 * 10);
-        // 取消服务器获取自身Ip地址和提交的host进行匹配
         ftp.setRemoteVerificationEnabled(false);
-        //设置ftp编码
         String encoding = Objects.nonNull(config.get("encoding")) ? config.get("encoding").toString() : "UTF-8";
         ftp.setControlEncoding(encoding);
-        ftp.setFileType(BINARY_FILE_TYPE);//设置文件编码类型为二进制文件,
+        ftp.setFileType(BINARY_FILE_TYPE);
         return ftp;
     }
 
+    /**
+     * 根据数据源ID和源路径下载文件。
+     *
+     * @param datasourceId 数据源ID,用于查询FTP连接配置。
+     * @param sourcePath   要下载的文件路径。
+     * @return 下载结果,包含文件内容的映射。
+     * @throws Exception 如果下载过程中发生任何异常。
+     */
     public Map<String, Object> downloadByDataSourceId(String datasourceId, String sourcePath) throws Exception {
         String config = queryConnectionStr(datasourceId);
-        return download(config,sourcePath);
+        return download(config, sourcePath);
     }
 
     /**
-     * @param connectionConfig 连接fpt的连接信息
-     * @param sourcePath       组装好的文件名称
-     * @return
+     * 使用提供的连接配置和文件路径下载文件。
+     *
+     * @param connectionConfig FTP连接配置。
+     * @param sourcePath       要下载的文件路径。
+     * @return 下载结果,包含文件内容的映射。
      */
     public Map<String, Object> download(String connectionConfig, String sourcePath) {
-
-        Map connectionConfigMaps = DataFormatUtil.toMap(connectionConfig);
+        // 解析连接配置
+        Map<?, ?> connectionConfigMaps = DataFormatUtil.toMap(connectionConfig);
         FTPClient ftp = null;
         try {
             List<Object> fileList = new ArrayList<>();
             fileList.add(sourcePath);
-            String basePath = Objects.toString(connectionConfigMaps.get("basePath")); //根路径
-            ftp = createFtpClient(connectionConfigMaps);
+            // 设置FTP工作目录
+            String basePath = Objects.toString(connectionConfigMaps.get("basePath"));
+            ftp = createFtpClient((Map<String, Object>) connectionConfigMaps);
             if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
-                System.err.println("未连接到FTP,用户名或密码错误。");
+                logger.error("未连接到FTP,用户名或密码错误。");
                 ftp.logout();
                 return UniReturnUtil.fail("未连接到FTP,用户名或密码错误。");
             }
             if (StringUtils.hasLength(basePath)) {
                 ftp.changeWorkingDirectory(basePath);
             }
-            String rootPath = ftp.printWorkingDirectory(); //ftp根目录
+            // 检查FTP根目录
+            String rootPath = ftp.printWorkingDirectory();
             FTPFile[] ftpFiles = ftp.listFiles(rootPath);
             if (ftpFiles.length == 0) {
-                System.err.println("没有找到文件");
+                logger.error("没有找到文件");
                 ftp.logout();
                 return UniReturnUtil.fail("没有找到文件");
             }
+            // 下载文件
             List<File> files = new ArrayList<>();
             for (FTPFile ftpFile : ftpFiles) {
                 String tpFileName = ftpFile.getName();
-                System.err.println(tpFileName);
                 if (fileList.contains(tpFileName)) {
                     String path = System.getProperty("user.dir") + File.separator + "ftp" + File.separator + ftpFile.getName();
                     File targetFile = new File(path);
                     files.add(targetFile);
                     try (FileOutputStream fileOutputStream = new FileOutputStream(targetFile)) {
                         ftp.retrieveFile(ftpFile.getName(), fileOutputStream);
-                    } catch (Exception e) {
-                        System.err.println("数据下载异常".concat(UniReturnUtil.getMessage(e)));
                     }
                 }
             }
-            ftp.logout();//退出ftp
+            ftp.logout();
+            // 解压并读取文件内容
             List<String> fileContent = new ArrayList<>();
             for (File ftpFile : files) {
-                String path = System.getProperty("user.dir") + File.separator + "ftp" + File.separator + ftpFile.getName();
-                File targetFile = new File(path);
-                if (targetFile.exists()) {
-                    try (GZIPInputStream gzipInputStream = new GZIPInputStream(Files.newInputStream(targetFile.toPath()));
-                         ByteArrayOutputStream baos = new ByteArrayOutputStream()
-                    ) {
+                if (ftpFile.exists()) {
+                    try (GZIPInputStream gzipInputStream = new GZIPInputStream(Files.newInputStream(ftpFile.toPath()));
+                         ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                         byte[] buf = new byte[BUFFER_SIZE];
                         int len;
                         while ((len = gzipInputStream.read(buf, 0, BUFFER_SIZE)) != -1) {
                             baos.write(buf, 0, len);
                         }
                         fileContent.add(baos.toString(StandardCharsets.UTF_8));
-                    } catch (Exception e) {
-                        System.err.println("数据解压异常".concat(UniReturnUtil.getMessage(e)));
                     }
                 }
             }
@@ -139,32 +148,43 @@ public class FTP {
         } catch (Exception e) {
             return UniReturnUtil.fail("fpt读取文件异常".concat(UniReturnUtil.getMessage(e)));
         } finally {
+            // 关闭FTP连接
             try {
                 if (null != ftp) {
                     ftp.disconnect();
                 }
             } catch (Exception ex) {
-                System.out.println("ftp关闭时异常:".concat(ex.getMessage()));
+                logger.error("ftp关闭时异常:".concat(ex.getMessage()));
             }
         }
     }
 
-
-
+    /**
+     * 根据数据源ID查询FTP连接配置信息。
+     *
+     * @param datasourceId 数据源ID。
+     * @return FTP连接字符串。
+     * @throws Exception 如果查询过程中发生任何异常。
+     */
     private static String queryConnectionStr(String datasourceId) throws Exception {
+        // 从数据库查询FTP配置
         List<Map<String, Object>> result = DATA_BASE.query(Config.getCenterConnectionStr(), """
                 select host,httpheaders,httpbody
                 from datasource
                 where datasourceid = ? limit 1 offset 0""", datasourceId);
         if (result.isEmpty()) {
-            throw new RuntimeException("数据源错误:没有找到数据源");
+            throw new ConnectionNotFoundException("数据源错误:没有找到数据源");
         }
-        return result.stream().findFirst().map(it -> {
+        // 将查询结果转换为连接字符串
+        Optional<String> optional = result.stream().findFirst().map(it -> {
             HashMap<String, Object> hashMap = new HashMap<>();
             hashMap.put("url", it.get("host"));
             hashMap.put("headers", it.get("httpheaders"));
             hashMap.put("body", it.get("httpbody"));
             return DataFormatUtil.toString(hashMap);
-        }).get();
+        });
+
+        return optional.orElse(null);
     }
 }
+

+ 66 - 30
src/main/java/com/scbfkj/uni/process/Http.java

@@ -1,5 +1,6 @@
 package com.scbfkj.uni.process;
 
+import com.scbfkj.uni.exceptions.ConnectionNotFoundException;
 import com.scbfkj.uni.library.DataFormatUtil;
 import com.scbfkj.uni.library.UniReturnUtil;
 import com.scbfkj.uni.system.Config;
@@ -10,6 +11,8 @@ import org.apache.http.entity.ByteArrayEntity;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 import org.apache.http.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
@@ -17,28 +20,46 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 
+/**
+ * Http客户端类,用于执行Web API操作。
+ */
 public class Http {
 
+    // 数据库实例
     private static final DataBase DATA_BASE = new DataBase();
-
-    private final static PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
+    // 日志记录器
+    private static final Logger LOGGER = LoggerFactory.getLogger(Http.class);
+    // 连接管理器,用于复用HTTP连接
+    private static final PoolingHttpClientConnectionManager CM = new PoolingHttpClientConnectionManager();
+    // 配置好的HTTP客户端实例
     private static HttpClient httpClient;
 
+    // 初始化HTTP客户端,设置连接池参数
     static {
-
-        cm.setMaxTotal(100); // 设置最大连接数
-        cm.setDefaultMaxPerRoute(20); // 设置每个路由的最大连接数
+        CM.setMaxTotal(100); // 设置最大连接数
+        CM.setDefaultMaxPerRoute(20); // 设置每个路由的最大连接数
+        // 使用自定义的连接管理器创建HTTP客户端
         httpClient = HttpClients.custom()
-                .setConnectionManager(cm)
+                .setConnectionManager(CM)
                 .build();
-
     }
 
-
+    /**
+     * 根据数据源ID执行Web API操作。
+     *
+     * @param dataSourceId 数据源ID,用于查询API连接配置。
+     * @param headers 请求头信息,可选。
+     * @param method HTTP请求方法,默认为"post"。
+     * @param defaultBody 请求体内容,默认为null。
+     * @return 执行结果,为一个Map对象。
+     * @throws Exception 如果执行过程中出现错误,则抛出异常。
+     */
     public Map<String, Object> execWebApiByDataSourceId(String dataSourceId, Object headers, String method, Object defaultBody) throws Exception {
+        // 根据数据源ID查询连接配置
         Map<String, Object> config = queryConnectionStr(dataSourceId);
 
         String host;
+        // 如果请求头、方法或请求体未提供,则使用配置中的默认值
         if (Objects.isNull(headers)) {
             headers = DataFormatUtil.toMap(config.get("headers"));
         }
@@ -49,48 +70,53 @@ public class Http {
             defaultBody = config.get("body");
         }
         host = config.get("host").toString();
+        // 执行Web API请求
         return execWebApi(headers, method, defaultBody, host);
     }
 
+    /**
+     * 执行Web API请求。
+     *
+     * @param headers 请求头信息。
+     * @param method HTTP请求方法。
+     * @param defaultBody 请求体内容。
+     * @param url 请求的URL。
+     * @return 执行结果,为一个Map对象。
+     */
     public Map<String, Object> execWebApi(Object headers, String method, Object defaultBody, String url) {
-
+        // 如果处于调试模式,则记录日志
         if (Config.isDebug()) {
-            System.out.println("url: " + DataFormatUtil.toString(url));
-            System.out.println("method: " + DataFormatUtil.toString(method));
-            System.out.println("headers: " + DataFormatUtil.toString(headers));
-            System.out.println("body: " + DataFormatUtil.toString(defaultBody));
+            LOGGER.info("url: {}", url);
+            LOGGER.info("method: {}",method);
+            LOGGER.info("headers: {}", headers);
+            LOGGER.info("body: {}", defaultBody);
         }
         HttpUriRequest request;
-
+        // 根据请求方法创建相应的HTTP请求对象,并设置请求体
         switch (method.toLowerCase()) {
-            case "get" -> {
-                request = new HttpGet(url);
-            }
+            case "get" -> request = new HttpGet(url);
             case "put" -> {
                 request = new HttpPut(url);
                 ((HttpPut) request).setEntity(new ByteArrayEntity(DataFormatUtil.toString(defaultBody).getBytes(StandardCharsets.UTF_8)));
             }
-            case "delete" -> {
-                request = new HttpDelete(url);
-            }
+            case "delete" -> request = new HttpDelete(url);
             default -> {
                 request = new HttpPost(url);
                 ((HttpPost) request).setEntity(new ByteArrayEntity(DataFormatUtil.toString(defaultBody).getBytes(StandardCharsets.UTF_8)));
             }
         }
 
-        if (headers instanceof Map hs) {
-
-            hs.forEach((k, v) -> {
-                request.addHeader((String) k, String.valueOf(v));
-            });
-
+        // 如果提供了请求头信息,则添加到请求中
+        if (headers instanceof Map<?,?> hs) {
+            hs.forEach((k, v) -> request.addHeader((String) k, String.valueOf(v)));
         }
 
         try {
+            // 执行HTTP请求并处理响应
             HttpResponse response = httpClient.execute(request);
             String contentType = response.getEntity().getContentType().getValue();
             int statusCode = response.getStatusLine().getStatusCode();
+            // 根据响应类型和状态码返回结果
             if (contentType.equalsIgnoreCase("application/octet-stream")) {
                 return UniReturnUtil.success(EntityUtils.toByteArray(response.getEntity()));
             }
@@ -101,26 +127,36 @@ public class Http {
                 return UniReturnUtil.fail(responseBody.toString());
             }
         } catch (Exception e) {
+            // 处理请求执行过程中的异常
             return UniReturnUtil.fail(e);
         }
-
     }
 
-
+    /**
+     * 根据数据源ID查询数据库,获取连接配置。
+     *
+     * @param datasourceId 数据源ID。
+     * @return 连接配置,为一个Map对象。
+     * @throws Exception 如果查询过程中出现错误或未找到配置,则抛出异常。
+     */
     private static Map<String, Object> queryConnectionStr(String datasourceId) throws Exception {
+        // 执行查询操作
         List<Map<String, Object>> result = DATA_BASE.query(Config.getCenterConnectionStr(), """
                 select host,httpheaders,httpbody
                 from datasource
                 where datasourceid = ?""", datasourceId);
+        // 如果未找到对应的配置,则抛出异常
         if (result.isEmpty()) {
-            throw new RuntimeException("数据源错误:没有找到数据源");
+            throw new ConnectionNotFoundException("数据源错误:没有找到数据源");
         }
+        // 处理查询结果,返回连接配置
         return result.stream().findFirst().map(it -> {
             HashMap<String, Object> hashMap = new HashMap<>();
             hashMap.put("url", it.get("host"));
             hashMap.put("headers", it.get("httpheaders"));
             hashMap.put("body", it.get("httpbody"));
             return hashMap;
-        }).get();
+        }).orElse(new HashMap<>());
     }
 }
+

+ 242 - 34
src/main/java/com/scbfkj/uni/process/IBMMQ.java

@@ -1,9 +1,8 @@
 package com.scbfkj.uni.process;
 
 
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.ibm.mq.MQException;
 import com.ibm.mq.jakarta.jms.MQQueueConnectionFactory;
+import com.scbfkj.uni.exceptions.ConnectionNotFoundException;
 import com.scbfkj.uni.library.DataFormatUtil;
 import com.scbfkj.uni.system.Config;
 import jakarta.jms.ConnectionFactory;
@@ -14,27 +13,44 @@ import org.springframework.jms.connection.CachingConnectionFactory;
 import org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter;
 import org.springframework.jms.core.JmsTemplate;
 
-import java.io.IOException;
 import java.util.*;
 
-
+/**
+ * IBM MQ客户端类,用于发送和接收消息。
+ */
 public class IBMMQ {
 
     private static final DataBase DATA_BASE = new DataBase();
     private JmsTemplate jmsTemplate = null;
 
-    private final ObjectMapper mapper = new ObjectMapper();
-
+    /**
+     * 根据数据源ID接收消息。
+     * 通过给定的数据源ID查询连接配置,并使用这些配置连接到指定的队列管理器,从指定的队列中接收消息。
+     *
+     * @param dataSourceId 数据源ID,用于查询连接字符串。
+     * @param channel      通道名称。
+     * @param queueManager 队列管理器名称。
+     * @param queueName    队列名称。
+     * @param ccsid        编码集ID。
+     * @param receiveTimeout 接收超时时间。
+     * @param pollSize     每次轮询的大小。
+     * @param retry        重试次数。
+     * @return 返回接收到的消息列表。
+     * @throws Exception 如果连接配置查询失败或消息接收过程中出现错误,则抛出异常。
+     */
     public List<String> receptionMessageByDataSourceId(String dataSourceId, String channel, String queueManager, String queueName, Long ccsid, Long receiveTimeout, Long pollSize, Long retry) throws Exception {
+        // 根据数据源ID查询连接配置
         Map<String, Object> config = queryConnectionStr(dataSourceId);
 
-        long port = 1414L;
+        long port = 1414L; // 默认端口号
+        // 从连接配置中解析主机名和端口号
         String host = Objects.toString(config.get("host"));
         if (host.contains(":")) {
             String[] split = host.split(":");
             port = Long.parseLong(split[1]);
             host = split[0];
         }
+        // 从连接配置中解析用户名和密码
         String username = null;
         String password = null;
         Object username1 = config.get("username");
@@ -45,75 +61,146 @@ public class IBMMQ {
         if (Objects.nonNull(password1)) {
             password = password1.toString();
         }
+        // 使用解析出的配置信息进行消息接收
         return receptionMessage(host, port, channel, queueManager, queueName, ccsid, username, password, receiveTimeout, pollSize, retry);
 
     }
 
+
+    /**
+     * 从指定队列接收消息的函数。
+     *
+     * @param host 主机地址。
+     * @param port 端口号。
+     * @param channel 频道或连接标识。
+     * @param queueManager 队列管理器名称。
+     * @param queueName 需要接收消息的队列名称。
+     * @param ccsid 编码集ID。
+     * @param username 连接认证的用户名。
+     * @param password 连接认证的密码。
+     * @param receiveTimeout 接收消息的超时时间。
+     * @param pollSize 每次轮询的最大消息数。如果为0,则默认为100。
+     * @param retry 接收消息失败后的最大重试次数。
+     * @return 返回接收到的消息列表。
+     * @throws JMSException 如果JMS操作失败,则抛出此异常。
+     */
     public List<String> receptionMessage(
             String host, Long port, String channel, String queueManager, String queueName, Long ccsid, String username, String password, Long receiveTimeout, Long pollSize, Long retry) throws JMSException {
+        // 初始化JmsTemplate用于消息接收
         JmsTemplate template = getJmsTemplate(host, port.intValue(), ccsid.intValue(), queueManager, channel, username, password);
 
+        // 设置接收超时时间
         jmsTemplate.setReceiveTimeout(receiveTimeout);
-        long maxSize = 100;
+
+        // 设置最大轮询消息数
+        long maxSize = 100; // 默认值
         if (pollSize > 0) {
             maxSize = pollSize;
         }
+
+        // 初始化最大重试次数
         int maxRetry = 0;
         List<String> result = new ArrayList<>();
 
-
+        // 不断尝试接收消息,直到满足退出条件
         while (true) {
             try {
+                // 尝试从指定队列接收消息
                 Message message = template.receive(queueName);
-                if (message == null) {
-                    break;
-                } else if (message instanceof TextMessage msg) {
-                    String text = msg.getText();
-                    result.add(text);
-                    if (result.size() >= maxSize) {
-                        break;
-                    }
-                }
+                // 检查是否需要退出循环
+                if (checkIsBreak(message, result, maxSize)) break;
             } catch (Exception e) {
+                // 捕获异常,增加重试计数
                 maxRetry++;
+                // 当重试次数超过设定值时,退出循环
                 if (maxRetry > retry) {
-                    if (Config.isDebug()) {
-                        e.printStackTrace();
-                    }
+                    // 清理JmsTemplate资源并返回当前结果
                     if (jmsTemplate != null) {
                         jmsTemplate = null;
                     }
-
                     return result;
                 }
             }
         }
-        return result;
+        return result; // 返回最终接收的消息列表
+    }
 
 
+    /**
+     * 检查是否应该中断处理消息的循环。
+     *
+     * @param message 需要检查的消息对象,如果为null表示找到终止条件。
+     * @param result 存储处理结果的列表,每处理一个消息,将其文本添加到列表中。
+     * @param maxSize 当结果列表的大小达到或超过此值时,视为找到终止条件。
+     * @return 如果未找到终止条件,返回true;反之,返回false。
+     * @throws JMSException 如果处理消息时发生错误。
+     */
+    private static boolean checkIsBreak(Message message, List<String> result, long maxSize) throws JMSException {
+        // 判断消息是否为null,若为null则认为找到了终止条件
+        boolean found = message == null;
+        // 如果消息是TextMessage类型,提取并存储其文本内容
+        if (message instanceof TextMessage msg) {
+            String text = msg.getText();
+            result.add(text);
+        }
+        // 如果结果列表的大小达到或超过最大值,认为找到了终止条件
+        if (result.size() >= maxSize) {
+            found = true;
+        }
+        // 返回相反的逻辑,即未找到终止条件为true,找到为false
+        return !found;
     }
 
 
+    /**
+     * 通过数据源ID发送单例消息。
+     * 此方法将指定的消息数据作为列表中的单个元素发送,适用于需要发送单一消息体的情况。
+     *
+     * @param dataSourceId 数据源ID,用于标识消息发送的目标数据源。
+     * @param channel 通道名称,指定消息将通过的通道。
+     * @param queueManager 队列管理器名称,指定消息将由哪个队列管理器处理。
+     * @param queueName 队列名称,指定消息将被发送到的队列。
+     * @param ccsid CCSID(字符集编码序列ID),指定消息的字符集。
+     * @param data 要发送的消息数据对象。
+     * @throws Exception 如果发送过程中遇到任何错误,则抛出异常。
+     */
     public void sendSingletonMessageByDataSourceId(
             String dataSourceId, String channel, String queueManager, String queueName, Long ccsid,
             Object data
     ) throws Exception {
+        // 使用Collections.singletonList将数据封装为列表,然后调用sendMessageByDataSourceId方法进行发送
         sendMessageByDataSourceId(dataSourceId, channel, queueManager, queueName, ccsid, Collections.singletonList(data));
     }
 
+
+    /**
+     * 根据数据源ID发送消息。
+     * 该方法通过查询数据源配置,获取连接信息,并使用提供的参数通过指定的通道、队列管理器和队列名称发送消息。
+     *
+     * @param dataSourceId 数据源ID,用于查询连接配置。
+     * @param channel 通信通道名称。
+     * @param queueManager 队列管理器名称。
+     * @param queueName 目标队列名称。
+     * @param ccsid 编码集标识符。
+     * @param data 要发送的消息数据列表。
+     * @throws Exception 如果发送消息过程中遇到任何错误,则抛出异常。
+     */
     public void sendMessageByDataSourceId(
             String dataSourceId, String channel, String queueManager, String queueName, Long ccsid,
             List<Object> data
     ) throws Exception {
+        // 根据dataSourceId查询连接配置
         Map<String, Object> config = queryConnectionStr(dataSourceId);
 
-        long port = 1414L;
+        long port = 1414L; // 默认端口号
+        // 从配置中解析主机名和端口号
         String host = Objects.toString(config.get("host"));
         if (host.contains(":")) {
             String[] split = host.split(":");
             port = Long.parseLong(split[1]);
             host = split[0];
         }
+        // 解析用户名和密码 from 配置
         String username = null;
         String password = null;
         Object username1 = config.get("username");
@@ -124,33 +211,69 @@ public class IBMMQ {
         if (Objects.nonNull(password1)) {
             password = password1.toString();
         }
+        // 发送消息
         sendMessage(host, port, channel, queueManager, queueName, ccsid, username, password, data);
     }
 
+
+    /**
+     * 发送单个消息到指定的队列。此方法封装了消息的发送过程,方便发送单个消息。
+     *
+     * @param host 主机地址,消息将从该主机发送。
+     * @param port 端口号,用于指定主机上的通信端口。
+     * @param channel 通道名称,用于连接到消息队列管理器。
+     * @param queueManager 队列管理器名称,负责管理消息队列。
+     * @param queueName 队列名称,指定消息将被发送到的队列。
+     * @param ccsid CCSID(Character Code Set Identifier),指定字符编码集。
+     * @param username 用户名,用于认证发送消息的用户。
+     * @param password 密码,与用户名一起用于认证。
+     * @param data 要发送的数据,该方法支持任意类型的数据对象。
+     * @throws JMSException 如果发送消息过程中发生任何JMS异常,则抛出。
+     */
     public void sendSingletonMessage(
             String host, Long port, String channel, String queueManager, String queueName, Long ccsid, String username, String password,
             Object data
     ) throws JMSException {
+        // 将数据封装为单元素列表,并调用sendMessage方法发送消息
         sendMessage(host, port, channel, queueManager, queueName, ccsid, username, password, Collections.singletonList(data));
     }
 
+
+    /**
+     * 发送消息到指定的队列
+     *
+     * @param host 主机地址
+     * @param port 端口号
+     * @param channel 频道或连接标识
+     * @param queueManager 队列管理器名称
+     * @param queueName 队列名称
+     * @param ccsid 编码集ID
+     * @param username 用户名,用于认证
+     * @param password 密码,用于认证
+     * @param data 要发送的消息数据列表
+     * @throws JMSException 如果发送消息过程中出现JMS异常
+     */
     public void sendMessage(
             String host, Long port, String channel, String queueManager, String queueName, Long ccsid, String username, String password,
             List<Object> data
     ) throws JMSException {
 
+        // 初始化JMS模板,配置连接信息
         JmsTemplate template = getJmsTemplate(host, port.intValue(), ccsid.intValue(), queueManager, channel, username, password);
 
         try {
+            // 遍历数据列表,发送每条消息
             for (Object it : data) {
 
                 execSend(template, it, queueName);
             }
 
         } catch (Exception e) {
+            // 若开启调试模式,打印异常堆栈
             if (Config.isDebug()) {
                 e.printStackTrace();
             }
+            // 出现异常时,清理jmsTemplate对象
             if (jmsTemplate != null) {
                 jmsTemplate = null;
             }
@@ -159,54 +282,126 @@ public class IBMMQ {
     }
 
 
+
+    /**
+     * 使用JmsTemplate发送消息到指定的队列。
+     *
+     * @param template JmsTemplate,用于发送消息的模板,封装了发送消息的详细逻辑。
+     * @param data 要发送的数据,可以是任意类型,最终会被转换为字符串格式发送。
+     * @param queueName 队列名称,指定消息要发送到的目标队列。
+     */
     private void execSend(
             JmsTemplate template,
             Object data,
             String queueName
     ) {
+        // 将数据转换为字符串格式
         String message = DataFormatUtil.toString(data);
+        // 使用JmsTemplate发送消息,将消息封装为TextMessage并发送到指定队列
         template.send(queueName, session -> session.createTextMessage(message));
     }
 
 
+
+    /**
+     * 创建一个 MQ 队列连接工厂实例。
+     *
+     * @param host 主机名,用于指定 MQ 服务器的地址。
+     * @param port 端口号,用于指定 MQ 服务器监听的端口。
+     * @param ccsid CCSID(Character Code Set Identifier),用于指定字符集。
+     * @param queueManager 队列管理器名,标识一个 MQ 队列管理器。
+     * @param channel 通道名,用于客户端和队列管理器之间的通信。
+     * @return 初始化后的 MQQueueConnectionFactory 实例。
+     * @throws JMSException 如果创建连接工厂时发生错误。
+     */
     private MQQueueConnectionFactory createMqQueueConnectionFactory(String host, int port, int ccsid, String queueManager, String channel) throws JMSException {
         MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
+        // 设置连接工厂的主机名
         mqQueueConnectionFactory.setHostName(host);
+        // 设置连接工厂的端口
         mqQueueConnectionFactory.setPort(port);
+        // 设置连接工厂的字符集
         mqQueueConnectionFactory.setCCSID(ccsid);
+        // 设置连接工厂的队列管理器名
         mqQueueConnectionFactory.setQueueManager(queueManager);
+        // 设置连接工厂的通道名
         mqQueueConnectionFactory.setChannel(channel);
+        // 设置连接工厂的传输类型为 TCP
         mqQueueConnectionFactory.setTransportType(1);
         return mqQueueConnectionFactory;
     }
 
 
+
+    /**
+     * 创建并配置一个JmsTemplate实例。
+     *
+     * @param factory CachingConnectionFactory的实例,用于设置JmsTemplate的消息工厂。
+     * @return 配置好的JmsTemplate实例,可用于发送消息。
+     */
     private JmsTemplate createJmsTemplate(CachingConnectionFactory factory) {
-        JmsTemplate jmsTemplate = new JmsTemplate();
-        jmsTemplate.setConnectionFactory(factory);
-        return jmsTemplate;
+        JmsTemplate template = new JmsTemplate();
+        template.setConnectionFactory(factory); // 设置消息工厂
+        return template;
     }
 
+
+    /**
+     * 创建一个 CachingConnectionFactory 实例。
+     * 此方法通过将一个给定的 ConnectionFactory 设置为缓存工厂的目标ConnectionFactory来配置 CachingConnectionFactory。
+     *
+     * @param factory 用于创建缓存工厂的目标ConnectionFactory。
+     * @return 配置好的 CachingConnectionFactory 实例。
+     */
     private CachingConnectionFactory createCachingConnectionFactory(ConnectionFactory factory) {
         CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
+        // 设置目标ConnectionFactory,以便CachingConnectionFactory可以使用它来创建连接
         cachingConnectionFactory.setTargetConnectionFactory(factory);
         return cachingConnectionFactory;
     }
 
+
+    /**
+     * 创建并配置一个 UserCredentialsConnectionFactoryAdapter 实例。
+     * 这个方法通过提供用户名、密码和一个ConnectionFactory,来创建一个已经设置了认证信息的ConnectionFactory适配器。
+     *
+     * @param username 将要用于认证的用户名。
+     * @param password 将要用于认证的密码。
+     * @param factory 是底层的ConnectionFactory,认证通过后将使用这个ConnectionFactory创建连接。
+     * @return 配置好的 UserCredentialsConnectionFactoryAdapter 实例,可用于进一步的使用。
+     */
     private UserCredentialsConnectionFactoryAdapter createAdapter(String username, String password, ConnectionFactory factory) {
         UserCredentialsConnectionFactoryAdapter adapter = new UserCredentialsConnectionFactoryAdapter();
-        adapter.setUsername(username);
-        adapter.setPassword(password);
-        adapter.setTargetConnectionFactory(factory);
+        adapter.setUsername(username); // 设置认证使用的用户名
+        adapter.setPassword(password); // 设置认证使用的密码
+        adapter.setTargetConnectionFactory(factory); // 设置目标ConnectionFactory
         return adapter;
     }
 
+    /**
+     * 获取一个配置好的JmsTemplate实例,用于与MQ队列进行交互。
+     *
+     * @param host MQ服务器的主机名。
+     * @param port MQ服务器的端口号。
+     * @param ccsid MQ服务器的字符集编码。
+     * @param queueManager MQ队列管理器的名称。
+     * @param channel 与MQ队列管理器通信的通道名称。
+     * @param username 连接MQ时的用户名。
+     * @param password 连接MQ时的密码。
+     * @return 配置好的JmsTemplate实例。
+     * @throws JMSException 如果在创建JMS连接工厂或模板时发生错误。
+     */
     private JmsTemplate getJmsTemplate(String host, int port, int ccsid, String queueManager, String channel, String username, String password) throws JMSException {
+        // 如果jmsTemplate尚未初始化,则进行初始化
         if (jmsTemplate == null) {
+            // 创建MQ队列连接工厂
             MQQueueConnectionFactory mqQueueConnectionFactory = createMqQueueConnectionFactory(host, port, ccsid, queueManager, channel);
+            // 使用用户名和密码适配器包装MQ队列连接工厂
             UserCredentialsConnectionFactoryAdapter adapter = createAdapter(username, password, mqQueueConnectionFactory);
+            // 创建缓存连接工厂,以提高性能
             CachingConnectionFactory cachingConnectionFactory = createCachingConnectionFactory(adapter);
 
+            // 创建并配置JmsTemplate实例
             jmsTemplate = createJmsTemplate(cachingConnectionFactory);
 
         }
@@ -214,16 +409,29 @@ public class IBMMQ {
     }
 
 
+
+    /**
+     * 查询指定数据源ID的连接字符串信息。
+     *
+     * @param datasourceId 数据源的唯一标识符。
+     * @return 返回一个包含主机名、密码和用户名的Map对象。
+     * @throws Exception 如果查询过程中发生错误,或者未找到指定的数据源ID,则抛出异常。
+     */
     private static Map<String, Object> queryConnectionStr(String datasourceId) throws Exception {
-        List<Map<String, Object>> result = DATA_BASE.query(Config.getCenterConnectionStr(), """
+        // 执行数据库查询,获取符合条件的第一条记录
+        Optional<Map<String, Object>> result = DATA_BASE.query(Config.getCenterConnectionStr(), """
                 select host,
                 password,
                 username,
                 from datasource
-                where datasourceid = ?""", datasourceId);
+                where datasourceid = ?""", datasourceId).stream().findFirst();
+
+        // 如果查询结果为空,抛出连接未找到异常
         if (result.isEmpty()) {
-            throw new RuntimeException("数据源错误:没有找到数据源");
+            throw new ConnectionNotFoundException("数据源错误:没有找到数据源");
         }
-        return result.stream().findFirst().get();
+
+        // 返回查询结果
+        return result.get();
     }
 }

+ 195 - 74
src/main/java/com/scbfkj/uni/process/JMS.java

@@ -1,7 +1,6 @@
 package com.scbfkj.uni.process;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
-import com.scbfkj.uni.system.Config;
 import jakarta.jms.ConnectionFactory;
 import jakarta.jms.JMSException;
 import jakarta.jms.Message;
@@ -13,7 +12,6 @@ import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
-import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.util.*;
@@ -21,156 +19,279 @@ import java.util.*;
 public class JMS {
 
 
-    private JmsTemplate jmsTemplate;
-
-    private final ObjectMapper mapper = new ObjectMapper();
-
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    /**
+     * 从指定队列接收消息并返回消息文本的列表。
+     * @param path 配置路径,用于获取JMS模板。
+     * @param className 类名称,用于获取JMS模板。
+     * @param queueName 需要接收消息的队列名称。
+     * @param receiveTimeout 接收消息的超时时间。
+     * @param pollSize 最大拉取消息数量。如果为0,则默认为100。
+     * @param retry 接收消息失败后的最大重试次数。
+     * @param args 传递给JMS模板的其他参数。
+     * @return 消息文本列表。
+     * @throws JMSException 如果JMS操作失败。
+     * @throws ClassNotFoundException 如果类加载失败。
+     * @throws InvocationTargetException 如果调用目标异常。
+     * @throws NoSuchMethodException 如果找不到方法。
+     * @throws InstantiationException 如果实例化异常。
+     * @throws IllegalAccessException 如果访问权限异常。
+     * @throws IOException 如果IO异常发生。
+     */
     public List<String> receptionMessage(String path, String className,
-                                         String queueName, Long receiveTimeout, Long pollSize, Long retry, Object... args) throws JMSException, MalformedURLException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
+                                         String queueName, Long receiveTimeout, Long pollSize, Long retry, Object... args) throws JMSException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, IOException {
+        // 获取JMS模板
         JmsTemplate template = getJmsTemplate(path, className, args);
+        template.setReceiveTimeout(receiveTimeout);
 
-
-        jmsTemplate.setReceiveTimeout(receiveTimeout);
+        // 设置最大拉取消息数量
         long maxSize = 100;
         if (pollSize > 0) {
             maxSize = pollSize;
         }
+
+        // 初始化最大重试次数
         int maxRetry = 0;
+        // 结果列表
         List<String> result = new ArrayList<>();
 
-
+        // 持续接收消息直到满足条件退出
         while (true) {
             try {
+                // 从队列接收消息
                 Message message = template.receive(queueName);
-                if (message == null) {
-                    break;
-                } else if (message instanceof TextMessage msg) {
+                boolean isNull = message == null;
+                // 如果消息不为空且是文本消息,则添加到结果列表中
+                if (message instanceof TextMessage msg) {
                     String text = msg.getText();
                     result.add(text);
+                    // 如果结果列表达到最大值,设置isNull为true以退出循环
                     if (result.size() >= maxSize) {
-                        break;
+                        isNull = true;
                     }
                 }
+                // 如果消息为空,退出循环
+                if (isNull) {
+                    break;
+                }
             } catch (Exception e) {
+                // 错误处理:增加重试次数,超过重试次数则返回当前结果
                 maxRetry++;
                 if (maxRetry > retry) {
-                    if (Config.isDebug()) {
-                        e.printStackTrace();
-                    }
-                    if (jmsTemplate != null) {
-                        jmsTemplate = null;
-                    }
-
                     return result;
                 }
             }
         }
         return result;
-
-
     }
 
 
+
+    /**
+     * 发送单例消息的方法。
+     * 这个方法通过指定的路径、类名、队列名,将数据以单例形式发送出去。
+     * 方法还会接收可变长度的参数 args,用于可能的额外操作或配置。
+     *
+     * @param path 指定的消息路径。
+     * @param className 需要调用的类的名称。
+     * @param queueName 消息将要发送到的队列名称。
+     * @param data 要发送的数据,此方法将其封装为单例列表。
+     * @param args 可变长度的参数,用于提供额外的数据或配置。
+     *
+     * @throws ClassNotFoundException 如果尝试加载类时未找到类。
+     * @throws InvocationTargetException 如果调用目标抛出异常。
+     * @throws NoSuchMethodException 如果未找到指定方法。
+     * @throws InstantiationException 如果实例化目标类时发生异常。
+     * @throws IllegalAccessException 如果没有权限访问指定方法。
+     * @throws IOException 如果发生输入/输出错误。
+     */
     public void sendSingletonMessage(String path, String className,
                                      String queueName,
                                      Object data, String... args
-    ) throws JMSException, MalformedURLException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
+    ) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, IOException {
+        // 将数据封装为单例列表,并调用sendMessage方法发送消息
         sendMessage(path, className, queueName, Collections.singletonList(data), args);
     }
 
+    /**
+     * 发送消息到指定的队列
+     *
+     * @param path 配置路径,用于获取JMS模板时的配置
+     * @param className 目标类名,用于实例化JMS模板
+     * @param queueName 队列名称,消息将发送到这个队列
+     * @param data 要发送的数据列表,每个数据对象都将被发送到队列
+     * @param args 可变参数,用于在获取JMS模板时传递给目标类的构造函数
+     * @throws IOException 在发送消息过程中可能抛出的IO异常
+     * @throws ClassNotFoundException 如果在反序列化过程中找不到类
+     * @throws InvocationTargetException 调用目标方法时抛出的目标异常
+     * @throws NoSuchMethodException 如果找不到指定的构造函数或方法
+     * @throws InstantiationException 在实例化目标类时抛出的异常
+     * @throws IllegalAccessException 在尝试访问或调用目标方法时没有足够权限
+     */
     public void sendMessage(String path, String className,
                             String queueName,
                             List<Object> data, String... args
-    ) throws JMSException, MalformedURLException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
+    ) throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
 
+        // 根据提供的路径、类名和参数数组获取JmsTemplate实例
         JmsTemplate template = getJmsTemplate(path, className, (Object[]) args);
 
-        try {
-            for (Object it : data) {
-
-                execSend(template, it, queueName);
-            }
-
-
-        } catch (Exception e) {
-            if (Config.isDebug()) {
-                e.printStackTrace();
-            }
-            if (jmsTemplate != null) {
-                jmsTemplate = null;
-            }
-
+        // 遍历数据列表,并对每个数据对象执行发送操作
+        for (Object it : data) {
+            execSend(template, it, queueName);
         }
     }
 
 
+
+    /**
+     * 使用JmsTemplate发送消息到指定的队列。
+     *
+     * @param template JmsTemplate,用于发送消息的模板,封装了发送消息的细节。
+     * @param data 要发送的数据对象,将被转换为JSON字符串。
+     * @param queueName 队列名称,指定消息要发送到的目标队列。
+     * @throws IOException 如果在将数据对象转换为JSON字符串时发生错误。
+     */
     private void execSend(
             JmsTemplate template,
             Object data,
             String queueName) throws IOException {
-        String message = mapper.writeValueAsString(data);
+        // 将数据对象转换为JSON字符串
+        String message = MAPPER.writeValueAsString(data);
 
+        // 使用JmsTemplate发送消息到指定队列
         template.send(queueName, session -> session.createTextMessage(message));
     }
 
 
-    private jakarta.jms.ConnectionFactory createConnectionFactory(String path, String className, Object... args) throws MalformedURLException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, ClassNotFoundException {
-        ClassLoader classLoader;
+
+    /**
+     * 创建一个Jakarta消息服务的ConnectionFactory实例。
+     * 此方法通过提供的路径和类名,动态加载指定的ConnectionFactory实现。
+     * 如果提供了路径,则会尝试从该路径加载对应的JAR文件,并以此JAR文件作为类加载器的一部分来创建ConnectionFactory。
+     * 如果未提供路径,则使用当前线程的上下文类加载器来尝试创建ConnectionFactory。
+     *
+     * @param path    外部JAR文件的相对路径,如果需要从外部加载实现。如果不需要外部加载,可以传入null或空字符串。
+     * @param className ConnectionFactory实现类的名称。
+     * @param args    传递给ConnectionFactory构造函数的参数数组。
+     * @return 创建的ConnectionFactory实例。
+     * @throws IOException                如果在读取文件或创建类加载器时发生IO异常。
+     * @throws NoSuchMethodException       如果在查找ConnectionFactory构造函数时未找到指定方法。
+     * @throws InvocationTargetException   如果在调用ConnectionFactory构造函数时发生异常。
+     * @throws InstantiationException     如果在实例化ConnectionFactory时发生异常。
+     * @throws IllegalAccessException    如果无权访问ConnectionFactory构造函数。
+     * @throws ClassNotFoundException    如果指定的类未找到。
+     */
+    private jakarta.jms.ConnectionFactory createConnectionFactory(String path, String className, Object... args) throws IOException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, ClassNotFoundException {
+
+        // 当提供路径参数时,尝试从该路径加载ConnectionFactory实现类
         if (Objects.nonNull(path) && !path.trim().isEmpty()) {
+            // 获取当前用户目录,拼接plugins目录和提供的路径,创建文件对象
             String userPath = System.getProperty("user.dir");
             File file = new File(userPath.concat(File.separator).concat("plugins").concat(File.separator).concat(path));
+            // 如果文件不存在,则抛出ClassNotFoundException
             if (!file.exists()) {
-                throw new RuntimeException("外部文件加载不存在:".concat(userPath).concat(File.separator).concat("plugins").concat(File.separator).concat(path));
+                throw new ClassNotFoundException("外部文件加载不存在:".concat(userPath).concat(File.separator).concat("plugins").concat(File.separator).concat(path));
             }
+            // 将文件转换为URL,用于URLClassLoader的构造
             URL url = file.toURI().toURL();
-            classLoader = new URLClassLoader(new URL[]{url}, Thread.currentThread().getContextClassLoader());
+
+            // 使用URLClassLoader加载指定路径下的JAR文件,并创建ConnectionFactory实例
+            try (URLClassLoader classLoader = new URLClassLoader(new URL[]{url}, Thread.currentThread().getContextClassLoader())) {
+                return getConnectionFactory(className, args, classLoader);
+            }
         } else {
-            classLoader = Thread.currentThread().getContextClassLoader();
+            // 若未提供路径,则使用当前线程的上下文类加载器创建ConnectionFactory实例
+            ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+            return getConnectionFactory(className, args, contextClassLoader);
         }
+    }
 
-        try {
-
-            Class<?> classExample = classLoader.loadClass(className); //获取类实例
-            Class<?>[] array = Arrays.stream(args).map(Object::getClass).toArray(Class[]::new);
-            Constructor<?> constructor;
-            constructor = classExample.getConstructor(array);
 
-            Object o = constructor.newInstance(args);
-            return (ConnectionFactory) o;
-        } catch (Exception exception) {
-            exception.printStackTrace();
-            throw new RuntimeException(exception);
-        } finally {
-            try {
-                if (classLoader instanceof URLClassLoader cl) {
-                    cl.close();
-                }
-            } catch (IOException e) {
-                throw new RuntimeException(e);
-            }
-        }
+    /**
+     * 通过给定的类名、参数和类加载器创建并返回一个ConnectionFactory实例。
+     *
+     * @param className 需要创建的ConnectionFactory类的名称。
+     * @param args 传递给ConnectionFactory构造函数的参数。
+     * @param classLoader 用于加载ConnectionFactory类的类加载器。
+     * @return ConnectionFactory实例。
+     * @throws ClassNotFoundException 当指定的类在类路径上不存在时抛出。
+     * @throws NoSuchMethodException 当找不到与给定参数匹配的构造函数时抛出。
+     * @throws InstantiationException 当类无法被实例化时抛出。
+     * @throws IllegalAccessException 当无法访问或实例化类时抛出。
+     * @throws InvocationTargetException 当构造函数抛出异常时抛出。
+     */
+    private ConnectionFactory getConnectionFactory(String className, Object[] args, ClassLoader classLoader) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
+        // 使用类加载器加载指定名称的类
+        Class<?> classExample = classLoader.loadClass(className);
+        // 将参数对象数组转换为类数组,以匹配构造函数参数
+        Class<?>[] array = Arrays.stream(args).map(Object::getClass).toArray(Class[]::new);
+        Constructor<?> constructor;
+        // 获取与提供的参数类型匹配的构造函数
+        constructor = classExample.getConstructor(array);
+
+        // 使用匹配的构造函数和参数创建对象实例
+        Object o = constructor.newInstance(args);
+        // 将对象实例强制转换为ConnectionFactory类型并返回
+        return (ConnectionFactory) o;
     }
 
 
+
+    /**
+     * 创建一个 CachingConnectionFactory 实例。
+     * 此方法通过将提供的 jakarta.jms.ConnectionFactory 实例设置为 CachingConnectionFactory 的目标ConnectionFactory来配置 CachingConnectionFactory。
+     *
+     * @param factory jakarta.jms.ConnectionFactory类型的实例,将被设置为CachingConnectionFactory的目标ConnectionFactory。
+     * @return 返回一个配置好的CachingConnectionFactory实例。
+     */
     private CachingConnectionFactory createCachingConnectionFactory(jakarta.jms.ConnectionFactory factory) {
         CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
+        // 设置目标ConnectionFactory为传入的factory参数
         cachingConnectionFactory.setTargetConnectionFactory(factory);
         return cachingConnectionFactory;
     }
 
 
-    private JmsTemplate getJmsTemplate(String path, String className, Object... args) throws MalformedURLException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
-        if (jmsTemplate == null) {
-            jakarta.jms.ConnectionFactory connectionFactory = createConnectionFactory(path, className, args);
-            CachingConnectionFactory cachingConnectionFactory = createCachingConnectionFactory(connectionFactory);
-            jmsTemplate = createJmsTemplate(cachingConnectionFactory);
-        }
-        return jmsTemplate;
+
+    /**
+     * 创建并返回一个JmsTemplate实例,该实例配置了基于给定参数的连接工厂。
+     *
+     * @param path 提供了连接工厂配置信息的路径,可以是文件路径或资源路径。
+     * @param className 连接工厂的类名,用于实例化连接工厂。
+     * @param args 传递给连接工厂构造函数的参数数组。
+     * @return 配置好的JmsTemplate实例,可用于发送和接收JMS消息。
+     * @throws IOException 如果在读取配置文件时发生IO错误。
+     * @throws ClassNotFoundException 如果指定的类名无法找到。
+     * @throws InvocationTargetException 如果调用构造函数时发生异常。
+     * @throws NoSuchMethodException 如果找不到指定的构造函数。
+     * @throws InstantiationException 如果类无法实例化。
+     * @throws IllegalAccessException 如果没有权限实例化类。
+     */
+    private JmsTemplate getJmsTemplate(String path, String className, Object... args) throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
+
+        // 根据提供的路径、类名和参数创建连接工厂
+        jakarta.jms.ConnectionFactory connectionFactory = createConnectionFactory(path, className, args);
+
+        // 创建一个缓存连接工厂,以提高性能
+        CachingConnectionFactory cachingConnectionFactory = createCachingConnectionFactory(connectionFactory);
+
+        // 基于缓存的连接工厂创建并返回JmsTemplate实例
+        return createJmsTemplate(cachingConnectionFactory);
+
     }
 
+
+    /**
+     * 创建并配置一个 JmsTemplate 实例。
+     *
+     * @param factory CachingConnectionFactory的实例,用于设置JmsTemplate的消息工厂。
+     * @return 配置好的JmsTemplate实例,可用于发送消息。
+     */
     private JmsTemplate createJmsTemplate(CachingConnectionFactory factory) {
         JmsTemplate jmsTemplate = new JmsTemplate();
-        jmsTemplate.setConnectionFactory(factory);
+        jmsTemplate.setConnectionFactory(factory); // 设置消息工厂
         return jmsTemplate;
     }
 }

+ 81 - 20
src/main/java/com/scbfkj/uni/process/Kafka.java

@@ -22,9 +22,9 @@ import java.util.*;
 public class Kafka {
 
     // 因为生产者是线程安全的所以相同的连接只需要一个生产者实例 不需要对象池
-    public static final Map<String, Producer<String, String>> producerMap = new HashMap<>();
+    public static final Map<String, Producer<String, String>> PRODUCER_MAP = new HashMap<>();
     //    消费者是非线程安全的所以需要一个对象池
-    private static final KeyedObjectPool<String, Consumer<String, String>> consumerPool = new GenericKeyedObjectPool<>(new BaseKeyedPooledObjectFactory<>() {
+    private static final KeyedObjectPool<String, Consumer<String, String>> CONSUMER_POOL = new GenericKeyedObjectPool<>(new BaseKeyedPooledObjectFactory<>() {
         @Override
         public Consumer<String, String> create(String key) throws Exception {
             Map<String, Object> connectConfigMaps = (Map<String, Object>) DataFormatUtil.stringToMap(key);
@@ -41,55 +41,112 @@ public class Kafka {
         }
     });
 
+    /**
+     * 发送单例消息的辅助方法。
+     * 通过给定的连接和主题,将数据作为单个消息项发送。
+     *
+     * @param connection 表示消息连接的字符串,用于建立或标识消息发送所需的连接。
+     * @param topic 消息的主题,标识消息的类型或目标。
+     * @param datas 要发送的数据,该方法将其封装为一个列表,即使实际只包含一个元素。
+     * @return 返回一个包含发送结果的Map,具体结果取决于实际的消息发送实现。
+     * @throws Exception 如果发送过程中遇到任何错误,将抛出异常。
+     */
     public static Map<String, Object> sendSingletonMessage(String connection, String topic, Object datas) throws Exception {
+        // 将数据封装为单个元素的列表,并调用sendMessage方法发送消息
         return sendMessage(connection, topic, Collections.singletonList(datas));
     }
 
-    public static Map<String, Object> sendMessage(String connection, String topic, List<Object> datas) throws Exception {
+/**
+ * 发送消息到指定主题
+ *
+ * @param connection 连接配置信息,用于创建生产者
+ * @param topic 消息将要发送到的主题
+ * @param datas 要发送的消息数据列表,数据类型为Object
+ * @return 返回一个Map,包含发送结果的信息,如果发送失败,会返回错误信息
+ * @throws Exception 如果创建生产者或发送消息过程中出现错误,将抛出异常
+ */
+public static Map<String, Object> sendMessage(String connection, String topic, List<Object> datas) throws Exception {
 
-        if (Objects.isNull(datas) || datas.isEmpty()) {
-            return UniReturnUtil.fail("数据为空");
-        }
-
-        List<Object> sendResult = new ArrayList<>();
-        Producer<String, String> producer = createProducer(connection);
-//            多线程发送
-        datas.parallelStream().forEach(it -> {
-            sendResult.add(producer.send(new ProducerRecord<>(topic, DataFormatUtil.toString(it))));
-        });
-        return UniReturnUtil.success(sendResult);
+    // 检查消息数据列表是否为空,如果为空,则返回失败结果
+    if (Objects.isNull(datas) || datas.isEmpty()) {
+        return UniReturnUtil.fail("数据为空");
     }
 
-    private synchronized static Producer<String, String> createProducer(String connectionStr) throws JsonProcessingException {
-        if (producerMap.containsKey(connectionStr)) {
-            return producerMap.get(connectionStr);
+    List<Object> sendResult = new ArrayList<>();
+    Producer<String, String> producer = createProducer(connection);
+    // 使用并行流来加速消息发送过程,逐个发送数据,并将发送结果添加到发送结果列表中
+    datas.parallelStream().forEach(it -> {
+        sendResult.add(producer.send(new ProducerRecord<>(topic, DataFormatUtil.toString(it))));
+    });
+    // 发送完成后,返回发送结果
+    return UniReturnUtil.success(sendResult);
+}
+
+
+    /**
+     * 创建并返回一个与给定连接字符串关联的Kafka生产者实例。如果该连接字符串已经存在一个对应的生产者实例,则直接返回该实例,实现生产者的缓存复用。
+     * 这个方法是同步的,以避免多线程环境下的并发问题。
+     *
+     * @param connectionStr 用于配置Kafka生产者的连接字符串,将被解析为配置映射。
+     * @return 配置好的Kafka生产者实例。
+     * @throws JsonProcessingException 当连接字符串解析为映射时,如果发生JSON处理错误则抛出。
+     */
+    private static synchronized  Producer<String, String> createProducer(String connectionStr) throws JsonProcessingException {
+        // 检查是否已经存在对应连接字符串的生产者实例,如果存在直接返回。
+        if (PRODUCER_MAP.containsKey(connectionStr)) {
+            return PRODUCER_MAP.get(connectionStr);
         }
+
+        // 将连接字符串解析为配置映射。
         Map<String, Object> connectConfigMaps = (Map<String, Object>) DataFormatUtil.stringToMap(connectionStr);
+
+        // 配置Kafka生产者的额外参数,例如请求超时时间、最大请求大小、压缩类型以及键值对的序列化方式。
         connectConfigMaps.put("request.timeout.ms", 60000);
         connectConfigMaps.put("max.request.size", 10240000);
         connectConfigMaps.put("compression.type", "gzip");
         connectConfigMaps.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
         connectConfigMaps.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
 
+        // 使用配置映射创建一个新的Kafka生产者实例。
         KafkaProducer<String, String> kafkaProducer = new KafkaProducer<>(connectConfigMaps);
-        producerMap.put(connectionStr, kafkaProducer);
+
+        // 将新的生产者实例与连接字符串关联并保存到映射中。
+        PRODUCER_MAP.put(connectionStr, kafkaProducer);
+
+        // 返回新的生产者实例。
         return kafkaProducer;
     }
 
+    /**
+     * 从指定主题和组ID接收消息的方法。
+     *
+     * @param connectConfig 连接配置的字符串表示,用于配置Kafka消费者。
+     * @param topic 需要订阅的主题名称。
+     * @param groupId 消费者组ID,如果为null或空,则不会设置。
+     * @return 一个包含接收到的消息列表的Map,如果没有任何消息,则列表为空。
+     * @throws Exception 如果发生任何异常,则抛出异常。
+     */
     public static Map<String, Object> receptionMessage(String connectConfig, String topic, String groupId) throws Exception {
+        // 将连接配置从字符串转换为Map形式,并设置键值对序列化器为StringDeserializer
         Map<String, Object> connectConfigMaps = (Map<String, Object>) DataFormatUtil.stringToMap(connectConfig);
         connectConfigMaps.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
         connectConfigMaps.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
+        // 如果组ID非null或空,则添加到配置中
         if (Objects.nonNull(groupId)) {
             connectConfigMaps.put(ConsumerConfig.GROUP_ID_CONFIG, groupId);
         }
 
+        // 将配置Map转换回字符串,用于从消费者池获取消费者
         String key = DataFormatUtil.toString(connectConfigMaps);
-        Consumer<String, String> consumer = consumerPool.borrowObject(key);
+        // 从消费者池借出一个消费者实例
+        Consumer<String, String> consumer = CONSUMER_POOL.borrowObject(key);
         try {
             List<String> messageList = new ArrayList<>();
+            // 订阅指定的主题
             consumer.subscribe(Collections.singleton(topic));
+            // 拉取消息记录
             ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(1000));
+            // 遍历记录,收集非空且非"{}"的消息值
             for (ConsumerRecord<String, String> record : records.records(topic)) {
                 String readValue = record.value().trim();
                 if (!StringUtils.hasLength(readValue) || readValue.equals("{}")) {
@@ -97,14 +154,18 @@ public class Kafka {
                 }
                 messageList.add(readValue);
             }
+            // 异步提交消费位点
             consumer.commitAsync();
 
+            // 如果处于调试模式,打印消息列表
             if (Config.isDebug()) {
                 System.out.println(DataFormatUtil.toString(messageList));
             }
+            // 返回成功结果,包含消息列表
             return UniReturnUtil.success(messageList);
         } finally {
-            consumerPool.returnObject(key, consumer);
+            // 将消费者实例归还给池
+            CONSUMER_POOL.returnObject(key, consumer);
         }
     }
 }

+ 101 - 19
src/main/java/com/scbfkj/uni/process/RabbitMQ.java

@@ -13,60 +13,94 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-
+/**
+ * RabbitMQ消息处理类,提供接收和发送消息的接口。
+ */
 public class RabbitMQ {
 
-
+    // JmsTemplate用于消息发送和接收
     private JmsTemplate jmsTemplate;
 
+    // ObjectMapper用于对象与JSON字符串之间的转换
     private final ObjectMapper mapper = new ObjectMapper();
 
+    /**
+     * 从指定队列接收消息。
+     *
+     * @param host RabbitMQ服务器主机名。
+     * @param port RabbitMQ服务器端口。
+     * @param username 登录用户名。
+     * @param password 登录密码。
+     * @param virtualHost 虚拟主机名。
+     * @param queueName 需要接收消息的队列名称。
+     * @param receiveTimeout 接收消息的超时时间。
+     * @param pollSize 一次接收消息的最大数量。
+     * @param retry 接收消息失败后的最大重试次数。
+     * @return 返回接收到的消息列表。
+     * @throws JMSException 如果接收消息过程中发生JMS异常。
+     */
     public List<String> receptionMessage(
             String host, Long port, String username, String password, String virtualHost, String queueName, Long receiveTimeout, Long pollSize, Long retry) throws JMSException {
+        // 初始化JmsTemplate
         JmsTemplate template = getJmsTemplate(host, port.intValue(), username, password, virtualHost);
 
-
+        // 设置接收超时时间
         jmsTemplate.setReceiveTimeout(receiveTimeout);
+
+        // 设置最大接收消息数量
         long maxSize = 100;
         if (pollSize > 0) {
             maxSize = pollSize;
         }
+
+        // 设置最大重试次数
         int maxRetry = 0;
         List<String> result = new ArrayList<>();
 
-
+        // 循环接收消息直至满足条件退出
         while (true) {
             try {
+                // 从队列接收消息
                 Message message = template.receive(queueName);
                 if (message == null) {
-                    break;
+                    break; // 没有消息时退出循环
                 } else if (message instanceof TextMessage msg) {
+                    // 处理文本消息
                     String text = msg.getText();
                     result.add(text);
                     if (result.size() >= maxSize) {
-                        break;
+                        break; // 达到最大接收数量时退出循环
                     }
                 }
             } catch (Exception e) {
                 maxRetry++;
                 if (maxRetry > retry) {
+                    // 重试次数超过最大重试次数时退出
                     if (Config.isDebug()) {
                         e.printStackTrace();
                     }
                     if (jmsTemplate != null) {
                         jmsTemplate = null;
                     }
-
                     return result;
                 }
             }
         }
         return result;
-
-
     }
 
-
+    /**
+     * 发送单条消息到指定队列。
+     *
+     * @param host RabbitMQ服务器主机名。
+     * @param port RabbitMQ服务器端口。
+     * @param username 登录用户名。
+     * @param password 登录密码。
+     * @param virtualHost 虚拟主机名。
+     * @param queueName 需要发送消息的队列名称。
+     * @param data 要发送的消息内容对象。
+     * @throws JMSException 如果发送消息过程中发生JMS异常。
+     */
     public void sendSingletonMessage(
             String host, Long port, String username, String password, String virtualHost, String queueName,
             Object data
@@ -74,42 +108,68 @@ public class RabbitMQ {
         sendMessage(host, port, username, password, virtualHost, queueName, Collections.singletonList(data));
     }
 
+    /**
+     * 发送消息到指定队列。
+     *
+     * @param host RabbitMQ服务器主机名。
+     * @param port RabbitMQ服务器端口。
+     * @param username 登录用户名。
+     * @param password 登录密码。
+     * @param virtualHost 虚拟主机名。
+     * @param queueName 需要发送消息的队列名称。
+     * @param data 要发送的消息内容对象列表。
+     * @throws JMSException 如果发送消息过程中发生JMS异常。
+     */
     public void sendMessage(
             String host, Long port, String username, String password, String virtualHost, String queueName,
             List<Object> data
     ) throws JMSException {
 
+        // 初始化JmsTemplate
         JmsTemplate template = getJmsTemplate(host, port.intValue(), username, password, virtualHost);
 
         try {
-
+            // 遍历并发送消息
             for (Object datum : data) {
                 execSend(template, datum, queueName);
             }
-
-
         } catch (Exception e) {
+            // 处理发送异常
             if (Config.isDebug()) {
                 e.printStackTrace();
             }
             if (jmsTemplate != null) {
                 jmsTemplate = null;
             }
-
         }
     }
 
-
+    /**
+     * 将消息对象转换为JSON字符串并发送到指定队列。
+     *
+     * @param template JmsTemplate实例。
+     * @param data 要发送的消息内容对象。
+     * @param queueName 消息发送的目的队列。
+     * @throws IOException 如果对象转JSON过程中发生IO异常。
+     */
     private void execSend(
             JmsTemplate template,
             Object data,
             String queueName) throws IOException {
         String message = mapper.writeValueAsString(data);
-
         template.send(queueName, session -> session.createTextMessage(message));
     }
 
-
+    /**
+     * 创建ConnectionFactory实例。
+     *
+     * @param host RabbitMQ服务器主机名。
+     * @param port RabbitMQ服务器端口。
+     * @param username 登录用户名。
+     * @param password 登录密码。
+     * @param virtualHost 虚拟主机名。
+     * @return 返回创建的ConnectionFactory实例。
+     */
     private jakarta.jms.ConnectionFactory createConnectionFactory(String host, int port, String username, String password, String virtualHost) {
         RMQConnectionFactory connectionFactory = new RMQConnectionFactory();
         connectionFactory.setUsername(username);
@@ -120,14 +180,29 @@ public class RabbitMQ {
         return connectionFactory;
     }
 
-
+    /**
+     * 创建CachingConnectionFactory实例。
+     *
+     * @param factory ConnectionFactory实例。
+     * @return 返回创建的CachingConnectionFactory实例。
+     */
     private CachingConnectionFactory createCachingConnectionFactory(jakarta.jms.ConnectionFactory factory) {
         CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
         cachingConnectionFactory.setTargetConnectionFactory(factory);
         return cachingConnectionFactory;
     }
 
-
+    /**
+     * 获取或创建JmsTemplate实例。
+     *
+     * @param host RabbitMQ服务器主机名。
+     * @param port RabbitMQ服务器端口。
+     * @param username 登录用户名。
+     * @param password 登录密码。
+     * @param virtualHost 虚拟主机名。
+     * @return 返回JmsTemplate实例。
+     * @throws JMSException 如果创建JmsTemplate过程中发生JMS异常。
+     */
     private JmsTemplate getJmsTemplate(String host, int port, String username, String password, String virtualHost) throws JMSException {
         if (jmsTemplate == null) {
             jakarta.jms.ConnectionFactory connectionFactory = createConnectionFactory(host, port, username, password, virtualHost);
@@ -137,9 +212,16 @@ public class RabbitMQ {
         return jmsTemplate;
     }
 
+    /**
+     * 创建JmsTemplate实例。
+     *
+     * @param factory ConnectionFactory实例。
+     * @return 返回创建的JmsTemplate实例。
+     */
     private JmsTemplate createJmsTemplate(CachingConnectionFactory factory) {
         JmsTemplate jmsTemplate = new JmsTemplate();
         jmsTemplate.setConnectionFactory(factory);
         return jmsTemplate;
     }
 }
+

+ 50 - 50
src/main/java/com/scbfkj/uni/process/SocketClient.java

@@ -1,83 +1,83 @@
 package com.scbfkj.uni.process;
 
-import org.apache.commons.pool2.BaseKeyedPooledObjectFactory;
-import org.apache.commons.pool2.KeyedObjectPool;
-import org.apache.commons.pool2.PooledObject;
-import org.apache.commons.pool2.impl.DefaultPooledObject;
-import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
-
 import java.io.*;
-import java.net.*;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
 import java.util.ArrayList;
-import java.util.Hashtable;
 import java.util.List;
-import java.util.Map;
-
+/**
+ * Socket客户端类,用于发送消息和接收消息。
+ */
 public class SocketClient {
 
+    /**
+     * 向指定URL发送消息列表。
+     *
+     * @param url 指定的URL,格式为"host:port"。
+     * @param messages 要发送的消息列表。
+     * @param timeOut 连接超时时间,单位为毫秒。
+     * @throws IOException 如果发生IO异常。
+     */
+    public void sendMessage(String url, List<String> messages, Long timeOut) throws IOException {
+        // 从URL中解析出主机名和端口号
+        String[] strings = url.split(":");
+        String host = strings[0];
+        String port = strings[1];
 
-    private static final Map<String, Socket> sockets = new Hashtable<>();
-
-
-    public void sendMessage(String url, List<String> messages, Long timeOut) throws Exception {
-
-        Socket socket = sockets.get(url);
-        if (socket == null || socket.isClosed()) {
-             socket = getSocket(url, timeOut);
-        }
-
-        try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));) {
+        // 使用try-with-resources语句确保资源被正确关闭
+        try (Socket socket = new Socket(host, Integer.parseInt(port)); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));) {
+            socket.setSoTimeout(timeOut.intValue());  // 设置超时时间
 
+            // 遍历消息列表,发送每条消息
             for (String message : messages) {
-
                 writer.write(message);
                 writer.newLine();
             }
-            writer.flush();
-        } catch (IOException e) {
-            System.err.println("Error in client: " + e.getMessage());
+            writer.flush();  // 刷新输出流,确保消息被发送
         }
     }
 
-    public List<String> receptionMessage(String url, Long pollSize, Long timeOut) throws Exception {
-
-        Socket socket = sockets.get(url);
-        if (socket == null || socket.isClosed()) {
-            socket = getSocket(url, timeOut);
-        }
-
+    /**
+     * 从指定URL接收消息列表。
+     *
+     * @param url 指定的URL,格式为"host:port"。
+     * @param pollSize 本次接收的最大消息数量。
+     * @param timeOut 连接超时时间,单位为毫秒。
+     * @return 接收到的消息列表。
+     * @throws IOException 如果发生IO异常。
+     */
+    public List<String> receptionMessage(String url, Long pollSize, Long timeOut) throws IOException {
+        // 从URL中解析出主机名和端口号
+        String[] strings = url.split(":");
+        String host = strings[0];
+        String port = strings[1];
 
         List<String> result = new ArrayList<>();
+        // 使用try-with-resources语句确保资源被正确关闭
         try (
+                Socket socket = new Socket(host, Integer.parseInt(port));
                 BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
-            while (true) {
+            socket.setSoTimeout(timeOut.intValue());  // 设置超时时间
 
+            // 不断读取消息,直到达到接收上限或发生超时
+            while (true) {
                 String value = reader.readLine();
+                boolean isBreak = false;
                 if (value == null) {
-                    break;
+                    isBreak = true; // 读取结束或超时
                 } else {
                     result.add(value);
-                    if (result.size() == pollSize) {
-                        break;
+                    if (result.size() >= pollSize) {
+                        isBreak = true; // 达到接收上限
                     }
                 }
+                if (isBreak) {
+                    break;
+                }
             }
         } catch (SocketTimeoutException e) {
-            return result;
-        } catch (IOException e) {
-            System.err.println("Error in client: " + e.getMessage());
+            return result; // 超时,返回已接收的消息
         }
         return result;
     }
-
-    private Socket getSocket(String url, Long timeOut) throws IOException {
-        Socket socket;
-        String[] strings = url.split(":");
-        String host = strings[0];
-        String port = strings[1];
-        socket = new Socket(host, Integer.parseInt(port));
-        socket.setSoTimeout(timeOut.intValue());
-        sockets.put(url, socket);
-        return socket;
-    }
 }

+ 69 - 26
src/main/java/com/scbfkj/uni/process/Web.java

@@ -1,8 +1,11 @@
 package com.scbfkj.uni.process;
 
+import com.scbfkj.uni.exceptions.ConnectionNotFoundException;
 import com.scbfkj.uni.library.DataFormatUtil;
 import com.scbfkj.uni.library.UniReturnUtil;
 import com.scbfkj.uni.system.Config;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.MediaType;
@@ -14,13 +17,16 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-
+/**
+ * Web API调用类
+ */
 public class Web {
 
     private static final DataBase DATA_BASE = new DataBase();
 
-    private RestTemplate restTemplate; //webapi请求对象
+    private RestTemplate restTemplate; // Web API请求对象
 
+    private static final Logger logger = LoggerFactory.getLogger(Web.class);
 
     private String webapiURL;
 
@@ -30,8 +36,18 @@ public class Web {
     private Map<String, Object> baseHeader = new HashMap<>();
 
 
+    /**
+     * 根据数据源ID执行Web API
+     *
+     * @param dataSourceId 数据源ID
+     * @param headers 请求头信息,可选
+     * @param method HTTP请求方法,默认为"post"
+     * @param defaultBody 请求体内容,默认为空
+     * @return Web API执行结果
+     * @throws Exception 抛出异常的情况
+     */
     public Map<String, Object> execWebApiByDataSourceId(String dataSourceId, Object headers, String method, Object defaultBody) throws Exception {
-        Map<String, Object> config = queryConnectionStr(dataSourceId);
+        Map<String, Object> config = queryConnectionStr(dataSourceId); // 查询数据源配置
 
         String host;
         if (Objects.isNull(headers)) {
@@ -47,30 +63,36 @@ public class Web {
         return execWebApi(headers, method, defaultBody, host);
     }
 
+    /**
+     * 执行Web API
+     *
+     * @param headers 请求头信息
+     * @param method HTTP请求方法
+     * @param defaultBody 请求体内容
+     * @param url 请求的URL地址
+     * @return 执行结果
+     */
     public Map<String, Object> execWebApi(Object headers, String method, Object defaultBody, String url) {
 
         if (Config.isDebug()) {
-            System.out.println("headers: " + DataFormatUtil.toString(headers));
-            System.out.println("method: " + DataFormatUtil.toString(method));
-            System.out.println("body: " + DataFormatUtil.toString(defaultBody));
+            logger.info("headers: {}", headers);
+            logger.info("method: {}", method);
+            logger.info("body: {}", defaultBody);
         }
 
-
-        Map<String, Object> restTemplateResult = initWebApiParams(headers, method, url); // 通过连接配置 获取restTemplate
+        Map<String, Object> restTemplateResult = initWebApiParams(headers, method, url); // 初始化Web API参数
 
         if (!"0".equals(restTemplateResult.get("code"))) {
             return UniReturnUtil.fail(restTemplateResult.get("message").toString());
         }
-        if (headers instanceof Map) {
-            Map<String, Object> temeMap = (Map) headers;
-            if (!temeMap.isEmpty()) {
-                temeMap.putAll(baseHeader);
-                webApiHeader.clear();
-                for (String key : temeMap.keySet()) {
-                    webApiHeader.add(key, temeMap.get(key).toString());
-                }
+        if (headers instanceof Map<?, ?> temeMap) {
+            temeMap.putAll((Map) baseHeader);
+            webApiHeader.clear();
+            for (Map.Entry<?, ?> entry : temeMap.entrySet()) {
+                webApiHeader.add((String) entry.getKey(), DataFormatUtil.toString(entry.getValue()));
             }
         }
+
         try {
 
             Map<String, Object> result = sendWebApiRequest(defaultBody);
@@ -81,6 +103,12 @@ public class Web {
         }
     }
 
+    /**
+     * 发送Web API请求
+     *
+     * @param defaultBody 请求体内容
+     * @return 请求结果
+     */
     private Map<String, Object> sendWebApiRequest(Object defaultBody) {
         try {
             HttpEntity<Object> request = new HttpEntity<>(defaultBody, webApiHeader);
@@ -107,6 +135,14 @@ public class Web {
         }
     }
 
+    /**
+     * 初始化Web API参数
+     *
+     * @param headers 请求头信息
+     * @param method HTTP请求方法
+     * @param url 请求的URL地址
+     * @return 初始化结果
+     */
     private Map<String, Object> initWebApiParams(Object headers, String method, String url) {
         try {
 
@@ -115,22 +151,21 @@ public class Web {
                 if (Objects.isNull(webapiURL)) {
                     return UniReturnUtil.fail("webapi请求地址为空");
                 }
-                Object tempHeaders = headers; //需确定返回的是一个map对象还是字符串  headers: {ContentType:"JSON"}
+                Object tempHeaders = headers;
                 webApiHeader = new HttpHeaders();
                 if (Objects.isNull(tempHeaders)) {
                     webApiHeader.setContentType(MediaType.APPLICATION_JSON);
                 }
-                if (tempHeaders instanceof Map) {
-                    baseHeader = (Map) tempHeaders;
+                if (tempHeaders instanceof Map<?, ?> temp) {
+                    baseHeader = (Map<String, Object>) temp;
                     if (!baseHeader.isEmpty()) {
-                        for (String key : baseHeader.keySet()) {
-                            webApiHeader.add(key, baseHeader.get(key).toString());
+                        for (Map.Entry<String, Object> entry : baseHeader.entrySet()) {
+                            webApiHeader.add(entry.getKey(), DataFormatUtil.toString(entry.getValue()));
                         }
                     }
                 }
-                Object webMethod = method; //需确定返回的是一个map对象还是字符串  headers: {ContentType:"JSON"}
-                if (Objects.nonNull(webMethod)) {
-                    webapiMethod = webMethod.toString().toLowerCase();
+                if (Objects.nonNull(method)) {
+                    webapiMethod = ((Object) method).toString().toLowerCase();
                 } else {
                     webapiMethod = "post";
                 }
@@ -144,13 +179,20 @@ public class Web {
     }
 
 
+    /**
+     * 查询数据源连接字符串
+     *
+     * @param datasourceId 数据源ID
+     * @return 数据源配置信息
+     * @throws Exception 抛出异常的情况
+     */
     private static Map<String, Object> queryConnectionStr(String datasourceId) throws Exception {
         List<Map<String, Object>> result = DATA_BASE.query(Config.getCenterConnectionStr(), """
                 select host,httpheaders,httpbody
                 from datasource
                 where datasourceid = ?""", datasourceId);
         if (result.isEmpty()) {
-            throw new RuntimeException("数据源错误:没有找到数据源");
+            throw new ConnectionNotFoundException("数据源错误:没有找到数据源");
         }
         return result.stream().findFirst().map(it -> {
             HashMap<String, Object> hashMap = new HashMap<>();
@@ -158,6 +200,7 @@ public class Web {
             hashMap.put("headers", it.get("httpheaders"));
             hashMap.put("body", it.get("httpbody"));
             return hashMap;
-        }).get();
+        }).orElse(new HashMap<>());
     }
 }
+

+ 31 - 12
src/main/java/com/scbfkj/uni/process/ZeroMQ.java

@@ -1,28 +1,46 @@
 package com.scbfkj.uni.process;
 
-import org.apache.commons.pool2.*;
+import org.apache.commons.pool2.BasePooledObjectFactory;
+import org.apache.commons.pool2.ObjectPool;
+import org.apache.commons.pool2.PooledObject;
 import org.apache.commons.pool2.impl.DefaultPooledObject;
-import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
 import org.apache.commons.pool2.impl.GenericObjectPool;
 import org.zeromq.SocketType;
 import org.zeromq.ZContext;
 import org.zeromq.ZMQ;
 
-import java.util.*;
-
+import java.util.List;
+/**
+ * ZeroMQ类提供了发送消息的功能。
+ */
 public class ZeroMQ {
 
+    // 创建一个对象池,用于管理ZContext对象的创建、销毁和复用
     private static final ObjectPool<ZContext> contexts = new GenericObjectPool<>(new BasePooledObjectFactory<>() {
+        /**
+         * 创建一个新的ZContext对象。
+         * @return 新创建的ZContext对象。
+         */
         @Override
         public ZContext create() {
             return new ZContext();
         }
 
+        /**
+         * 将ZContext对象包装成PooledObject。
+         * @param zContext 要被包装的ZContext对象。
+         * @return 被包装成PooledObject的ZContext对象。
+         */
         @Override
         public PooledObject<ZContext> wrap(ZContext zContext) {
             return new DefaultPooledObject<>(zContext);
         }
 
+        /**
+         * 销毁ZContext对象,释放资源。
+         * @param p 被销毁的ZContext对象的包装对象。
+         * @throws Exception 如果销毁过程中出现异常,则抛出。
+         */
         @Override
         public void destroyObject(PooledObject<ZContext> p) throws Exception {
             p.getObject().close();
@@ -30,29 +48,30 @@ public class ZeroMQ {
         }
     });
 
-
+    /**
+     * 向指定URL发送一系列消息。
+     * @param url 目标URL,用于建立连接。
+     * @param messages 要发送的消息列表。
+     * @throws Exception 如果发送过程中出现异常,则抛出。
+     */
     public void sendMessage(String url, List<String> messages) throws Exception {
-
-//        ZMQ.Socket socket = getSocket(url);
-
+        // 从context对象池中获取一个ZContext对象
         ZContext context = null;
         synchronized (contexts) {
             context = contexts.borrowObject();
         }
         try {
+            // 遍历消息列表,发送每条消息
             for (String message : messages) {
                 ZMQ.Socket socket = context.createSocket(SocketType.REQ);
                 socket.connect(url);
                 socket.send(message, 0);
             }
         } finally {
+            // 操作完成后,将ZContext对象返回到对象池
             if (context != null) {
                 contexts.returnObject(context);
             }
         }
-
-
     }
-
-
 }

+ 125 - 39
src/main/java/com/scbfkj/uni/service/ControlService.java

@@ -1,11 +1,17 @@
 package com.scbfkj.uni.service;
 
+import com.scbfkj.uni.exceptions.ContainerNotFoundException;
+import com.scbfkj.uni.exceptions.ServiceNotFoundException;
+import com.scbfkj.uni.exceptions.ServiceTypeException;
 import com.scbfkj.uni.library.DataAliasGetUtil;
 import com.scbfkj.uni.library.DataFormatUtil;
 import com.scbfkj.uni.library.UniReturnUtil;
 import com.scbfkj.uni.process.DataBase;
 import com.scbfkj.uni.system.Config;
 import com.scbfkj.uni.system.ScheduleUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
 
 import java.io.File;
 import java.time.LocalDateTime;
@@ -15,119 +21,188 @@ import java.util.Objects;
 import java.util.Optional;
 import java.util.stream.Collectors;
 
+/**
+ * 控制服务类,提供与容器部署相关的信息查询功能。
+ */
 public class ControlService {
 
-    private final static String SERVICEINFO_WHERE_CONTAINERCODE = "select serviceid from containerdeploy where containercode=? ";
+    // 日志记录器,用于记录控制服务类的日志信息
+    private static final Logger LOGGER = LoggerFactory.getLogger(ControlService.class);
 
-    private final static String SERVICE_ID = "serviceid";
-    private final static String CODE = "code";
+    // 查询指定容器代码的部署服务信息的SQL语句
+    private static final String SERVICEINFO_WHERE_CONTAINERCODE = "select serviceid from containerdeploy where containercode=? ";
 
+    // SQL语句中服务ID的字段名称
+    private static final String SERVICE_ID = "serviceid";
+    // SQL语句中容器代码的字段名称
+    private static final String CODE = "code";
+
+    // 数据库操作实例,用于执行数据库相关操作
     private static final DataBase DATA_BASE = new DataBase();
 
-    public static Map<String, Object> stopServiceByContainerCode(String containerCode) {
+    // ... 这里可以添加其他方法 ...
 
-//        查询服务类型为主动采集的服务
+    /**
+     * 根据容器代码停止特定服务。
+     * 该方法首先查询与给定容器代码相关联的服务信息,然后尝试停止这些服务。
+     *
+     * @param containerCode 容器的代码,用于标识需要停止服务的容器。
+     * @return 返回一个包含停止结果的Map,其中键为服务代码,值为停止操作的结果列表。
+     */
+    public static Map<String, Object> stopServiceByContainerCode(String containerCode) {
 
+        // 查询与指定容器代码相关联的服务信息
         try {
             List<Map<String, Object>> serviceInfos = DATA_BASE.query(Config.getCenterConnectionStr(), SERVICEINFO_WHERE_CONTAINERCODE, containerCode);
-//        循环启动
 
+            // 对查询到的服务信息进行处理,尝试停止每个服务,并将结果按服务代码分组
             Map<String, List<Map<String, Object>>> results = serviceInfos.stream().map(it -> stop(it.get(SERVICE_ID).toString(), containerCode)).collect(Collectors.groupingBy(it -> it.get(CODE).toString()));
             return UniReturnUtil.success(results);
         } catch (Exception e) {
+            // 处理异常情况,返回失败结果
             return UniReturnUtil.fail(e);
         }
     }
 
-    public static Map<String, Object> startServiceByContainerCode(String containerCode) {
 
-//        查询服务类型为主动采集的服务
+    /**
+     * 根据容器代码启动相应服务。
+     *
+     * @param containerCode 容器代码,用于查询特定容器的服务信息。
+     * @return 返回一个包含启动结果的Map,其中键为服务代码,值为启动该服务的结果列表。
+     */
+    public static Map<String, Object> startServiceByContainerCode(String containerCode) {
+        // 查询指定容器代码的服务信息
         try {
             List<Map<String, Object>> serviceInfos = DATA_BASE.query(Config.getCenterConnectionStr(), SERVICEINFO_WHERE_CONTAINERCODE, containerCode);
+
+            // 对查询到的服务信息逐个启动,并按服务代码进行分组
             Map<String, List<Map<String, Object>>> results = serviceInfos.stream().map(it -> start(it.get(SERVICE_ID).toString(), containerCode)).collect(Collectors.groupingBy(it -> it.get(CODE).toString()));
+
+            // 返回成功结果,包含启动结果的分组信息
             return UniReturnUtil.success(results);
         } catch (Exception e) {
+            // 遇到异常返回失败结果,包含异常信息
             return UniReturnUtil.fail(e);
         }
     }
 
     /**
-     * 服务启动 主要用于前端或者第三方请求
+     * 启动指定ID的服务。该方法主要用于处理前端或第三方请求。
+     * 首先查询服务信息,根据服务类型决定是直接设置为运行中还是启动定时任务。
      *
-     * @param serviceId
-     * @return
+     * @param serviceId     服务的唯一标识符
+     * @param containerCode 容器代码,用于指定服务运行的环境或容器
+     * @return 返回一个包含操作结果的Map,成功则包含成功信息,失败则包含错误信息
      */
     public static Map<String, Object> start(String serviceId, String containerCode) {
         try {
+            // 从数据库中查询服务的配置信息,特别是任务类型
             List<Map<String, Object>> serviceInfoList = DATA_BASE.query(Config.getCenterConnectionStr(), "select tasktype from serviceinfo where serviceid=?", serviceId);
-
+            // 检查服务配置是否存在
             if (serviceInfoList.isEmpty()) {
                 return UniReturnUtil.fail("服务%s没有配置".formatted(serviceId));
             }
+
+            // 获取服务的配置信息
             Map<String, Object> serviceInfo = serviceInfoList.get(0);
             String taskType = serviceInfo.getOrDefault("tasktype", "0").toString();
+
+            // 更新服务状态为运行中
             updateServiceState(serviceId, containerCode, "1");
-            if (Objects.equals(taskType, "0")) {
-//            设置服务状态为运行中
 
+            if (Objects.equals(taskType, "0")) {
+                // 如果服务类型为0,表示该服务无需定时任务,只需设置为运行中即可
                 return UniReturnUtil.success(null);
             } else {
-                //启动定时任务:
-                boolean start = ScheduleUtil.startService(serviceId);
-                if (start) {
-                    return UniReturnUtil.success("启动成功");
-                } else {
-                    return UniReturnUtil.fail("启动失败");
-                }
+                // 如果服务类型不为0,启动对应的定时任务
+                ScheduleUtil.startService(serviceId);
+                return UniReturnUtil.success("启动成功");
             }
-        } catch (Exception e) {
+        } catch (Exception | ServiceTypeException | ServiceNotFoundException e) {
+            // 处理异常,并返回失败信息
             return UniReturnUtil.fail(e);
         }
     }
 
 
     /**
-     * 服务停止
+     * 停止指定服务
      *
-     * @param serviceId
-     * @return
+     * @param serviceId     服务的唯一标识符
+     * @param containerCode 容器代码,标识服务运行的容器
+     * @return 返回一个包含操作结果的Map,成功或失败的信息以及状态码
      */
     public static Map<String, Object> stop(String serviceId, String containerCode) {
-        Map<String, Object> cancel = ScheduleUtil.cancel(serviceId);
+        Map<String, Object> cancelResult = null;
+        // 尝试取消服务
+        try {
+            cancelResult = ScheduleUtil.cancel(serviceId);
+        } catch (InterruptedException e) {
+            LOGGER.warn(""); // 记录中断异常日志
+            Thread.currentThread().interrupt(); // 重新设置中断状态
+            return UniReturnUtil.fail("停止服务失败"); // 返回失败结果
+        }
 
-        boolean isCancel = Objects.equals(cancel.get(CODE), "0");
+        // 判断取消操作是否成功
+        boolean isCancel = Objects.equals(cancelResult.get(CODE), "0");
+        // 尝试清理数据并更新服务状态
         try {
             if (isCancel) {
-                DataBase.columns.clear();
-                DataBase.cacheDatas.clear();
-                DataBase.cacheConfigList.clear();
+                // 清理数据库列信息
+                DataBase.getColumns().clear();
+                // 清理缓存数据
+                DataBase.getCacheData().clear();
+                // 清理缓存配置列表
+                DataBase.getCacheConfigList().clear();
+                // 更新服务状态为停止
                 updateServiceState(serviceId, containerCode, "0");
             }
         } catch (Exception e) {
+            // 捕获异常并返回失败结果
             return UniReturnUtil.fail(e);
         }
+        // 返回停止操作的结果,成功或失败
         return UniReturnUtil.success("停止" + (isCancel ? "成功" : "失败"));
     }
 
+
+    /**
+     * 更新服务状态。
+     *
+     * @param serviceId     服务ID
+     * @param containerCode 容器代码
+     * @param state         状态码,"1" 表示启动服务,其他值表示停止服务
+     * @throws Exception 抛出异常的条件不明确,需要具体化
+     */
     private static void updateServiceState(String serviceId, String containerCode, String state) throws Exception {
+        // 当状态为 "1" 时,表示启动服务
         if (Objects.equals(state, "1")) {
 
+            // 查询当前未停止的服务状态与ID
             List<Map<String, Object>> mapList = DATA_BASE.query(Config.getCenterConnectionStr(), "select runstate,servicestateid from servicestate where stoptime is  null and  serviceid=? and containercode=?", serviceId, containerCode);
+            // 未找到对应的服务状态
             if (mapList.isEmpty()) {
 
+                // 查询服务名称
                 List<Map<String, Object>> result = DATA_BASE.query(Config.getCenterConnectionStr(), "select servicename from serviceinfo where serviceid=?", serviceId);
                 Object servicename = result.isEmpty() ? null : result.get(0).get("servicename");
+                // 查询容器ID
                 result = DATA_BASE.query(Config.getCenterConnectionStr(), "select containerid from container where containercode=?", containerCode);
                 Object containerid = result.isEmpty() ? null : result.get(0).get("containerid");
 
+                // 新增服务状态记录
                 DATA_BASE.update(Config.getCenterConnectionStr(), "insert into  servicestate(serviceid,starttime,containercode,runstate,workpath,servicename,containerid) values (?,?,?,'1',?,?,?)", serviceId, DataFormatUtil.toString(LocalDateTime.now()), containerCode, new File(".").getAbsolutePath(), servicename, containerid);
             } else {
+                // 已有服务状态记录,更新为启动状态
                 String serviceStateId = mapList.get(0).get("servicestateid").toString();
                 DATA_BASE.update(Config.getCenterConnectionStr(), "update servicestate set starttime=?,runstate='1',workpath = ? where  servicestateid = ? and containercode =?", DataFormatUtil.toString(LocalDateTime.now()), new File(".").getAbsolutePath(), serviceStateId, containerCode);
             }
         } else {
+            // 停止服务的逻辑处理
             List<Map<String, Object>> mapList = DATA_BASE.query(Config.getCenterConnectionStr(), "select servicestateid, runstate from servicestate where stoptime is  null and  serviceid=? and containercode=? order by servicestateid desc", serviceId, containerCode);
 
+            // 存在有效的服务状态记录,更新为停止状态
             if (!mapList.isEmpty()) {
                 String serviceStateId = mapList.get(0).get("servicestateid").toString();
                 DATA_BASE.update(Config.getCenterConnectionStr(), "update servicestate set stoptime=?,runstate='0' where  servicestateid = ? and containercode =?", DataFormatUtil.toString(LocalDateTime.now()), serviceStateId, containerCode);
@@ -136,38 +211,49 @@ public class ControlService {
     }
 
     /**
-     * 用用户启停定时任务 服务类型为4的服务
+     * 启动或停止定时任务的服务。
+     * 该方法用于处理用户对类型为4的定时任务的启动或停止请求。
+     * 根据传入的参数决定是启动还是停止服务,并处理相关的异常情况。
      *
-     * @param params
-     * @param statue
-     * @return
-     * @throws Exception
+     * @param params 包含请求所需参数的Map,预期包含服务ID和容器代码等信息。
+     * @param statue 用于指示启动("1")或停止("0")服务的字符串。
+     * @param all    一个布尔值,指示是否处理所有相关服务,无论是否提供服务ID。
+     * @return 返回一个Map,包含操作结果信息,如成功或失败的状态及消息。
+     * @throws Exception 如果操作失败或存在输入错误,可能会抛出异常,如ContainerNotFoundException。
      */
-
     public static Map<String, Object> startOrStop(Map<String, Object> params, String statue, boolean all) throws Exception {
+        // 从参数中获取服务ID和容器代码
         Optional<String> serviceIdOpt = DataAliasGetUtil.getValue(SERVICE_ID, params);
         Optional<String> containerCode = DataAliasGetUtil.getValue("containercode", params);
+
+        // 检查是否提供了必要的信息,并根据all参数决定是否继续执行
         if ((serviceIdOpt.isEmpty() || containerCode.isEmpty()) && !all) {
+            // 如果未提供服务ID且all为false,则返回失败结果
             return UniReturnUtil.fail("服务ID不能为空");
         } else if (serviceIdOpt.isPresent() && containerCode.isPresent()) {
-
+            // 如果同时提供了服务ID和容器代码,则根据statue决定是启动还是停止服务
             String serviceId = serviceIdOpt.get();
             if (Objects.equals(statue, "0")) {
+                // 停止服务
                 return stop(serviceId, containerCode.get());
             } else {
+                // 启动服务
                 return start(serviceId, containerCode.get());
             }
         } else if (containerCode.isPresent()) {
+            // 如果只提供了容器代码,且statue为"0",则停止相关服务
             if (Objects.equals(statue, "0")) {
                 stopServiceByContainerCode(containerCode.get());
-
                 return UniReturnUtil.success(true);
             } else {
+                // 如果只提供了容器代码,且statue为"1",则启动相关服务
                 startServiceByContainerCode(containerCode.get());
                 return UniReturnUtil.success(true);
             }
         } else {
-            throw new RuntimeException("请输入启动的容器编号");
+            // 如果既没有服务ID,也没有容器代码,则抛出容器未找到的异常
+            throw new ContainerNotFoundException("请输入启动的容器编号", null);
         }
     }
+
 }

+ 0 - 454
src/main/java/com/scbfkj/uni/service/DataProcessService.java

@@ -1,454 +0,0 @@
-package com.scbfkj.uni.service;
-
-import com.jayway.jsonpath.JsonPath;
-import com.scbfkj.uni.library.DataAliasGetUtil;
-import com.scbfkj.uni.library.DataFormatUtil;
-import com.scbfkj.uni.library.UniReturnUtil;
-import com.scbfkj.uni.library.script.DatabaseScriptUtil;
-import com.scbfkj.uni.library.script.JavaScriptEngineUtil;
-import com.scbfkj.uni.library.script.JsScriptEngineUtil;
-import com.scbfkj.uni.process.DataBase;
-import com.scbfkj.uni.system.Config;
-
-import java.io.File;
-import java.text.NumberFormat;
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.*;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-
-public class DataProcessService {
-
-    //    添加一个线程池
-// 创建一个固定大小的线程池,包含2个线程
-    private static final ExecutorService executor = Executors.newWorkStealingPool();
-    private final DataBase DATA_BASE = new DataBase();
-    private static final DatabaseScriptUtil DATABASE_SCRIPT_UTIL = new DatabaseScriptUtil();
-
-    public Map<String, Object> process(Map<String, Object> inData) {
-        String lifecycleid = null;
-        List<Map<String, Object>> resource = new ArrayList<>();
-        List<Map<String, Object>> preResource = new ArrayList<>();
-        resource.add(inData);
-        String serviceId = null;
-        LocalDateTime startDateTime = LocalDateTime.now();
-        Optional<String> serviceIdOpt;
-        String message = null;
-        Object algorithmlibraryid;
-
-        Map<String, Object> serviceInfo = null;
-
-        try {
-            serviceIdOpt = DataAliasGetUtil.getValue("serviceid", inData);
-            if (serviceIdOpt.isEmpty()) {
-                throw new RuntimeException("服务编号不能为空");
-            }
-            serviceId = serviceIdOpt.get();
-
-//        熔断
-//            查询服务运行状态
-            List<Map<String, Object>> serviceState = DATA_BASE.query(Config.getCenterConnectionStr(), """
-                    select  runstate
-                    from servicestate
-                    where serviceid =? and runstate = '1' and containercode=? order by servicestateid desc""", serviceId, Config.getContainerCode());
-            if (serviceState.isEmpty() || serviceState.get(0).get("runstate").equals("0")) {
-                throw new RuntimeException("服务没有运行");
-            }
-            List<Map<String, Object>> serviceInfoList = DATA_BASE.query(Config.getCenterConnectionStr(), """
-                    select serviceid,
-                                               servicename,
-                                               tasktype,
-                                               cronexpress,
-                                               urilist,
-                                               loopcount,
-                                               frequency,
-                                               enablelog
-                                        from serviceinfo
-                                        where serviceid = ?""", serviceId);
-            if (!serviceInfoList.isEmpty()) {
-                serviceInfo = serviceInfoList.get(0);
-            }
-
-
-            Optional<String> lifecycleidOpt = DataAliasGetUtil.getValue("lifecycleid", inData);
-
-            if (lifecycleidOpt.isEmpty()) {
-                lifecycleid = DataAliasGetUtil.createLifeCycleCol(Config.getContainerCode(), serviceId);
-                inData.put("lifecycleid", lifecycleid);
-            } else {
-                lifecycleid = lifecycleidOpt.get();
-            }
-            HashMap<String, Object> source = new HashMap<>();
-
-            List<Map<String, Object>> algorithmLibraries = DATA_BASE.query(Config.getCenterConnectionStr(), """
-                    select algorithmlibraryid,
-                           serviceid,
-                           computingexpression,
-                           preconditions,
-                           executionorder,
-                           algorithmdescription,
-                           algorithmsourcelibraryid
-                    from algorithmlibrary
-                    where serviceid = ? order by executionorder""", serviceId);
-
-
-            for (Map<String, Object> algorithmLibrary : algorithmLibraries) {
-
-                Map<String, Object> algorithmResult = null;
-
-                long execTime;
-
-                startDateTime = LocalDateTime.now();
-                long startTime = System.currentTimeMillis();
-                algorithmlibraryid = algorithmLibrary.get("algorithmlibraryid");
-                Object preConditions = algorithmLibrary.get("preconditions");
-                HashMap<String, Object> data = new HashMap<>();
-//                记录生命周期ID
-                data.put("lifecycleid", lifecycleid);
-                data.put("algorithmlibraryid", algorithmlibraryid);
-                source.put("args", resource);
-                source.put("algorithm", algorithmLibrary);
-                Map<String, Object> eval = null;
-
-
-                if (Objects.nonNull(preConditions)) {
-                    eval = JsScriptEngineUtil.eval(preConditions.toString(), resource);
-                }
-
-                if (Objects.nonNull(eval)) {
-                    HashMap<String, Object> preData = new HashMap<>();
-                    preResource.add(preData);
-
-                    preData.put("algorithmlibraryid", algorithmlibraryid);
-                    String preCode;
-                    preData.put("preResult", eval);
-                    if (!Objects.equals(eval.get("code"), "0")) {
-                        throw new RuntimeException(eval.get("message").toString());
-                    }
-                    preCode = eval.get("returnData").toString();
-
-
-                    preData.put("preCode", preCode);
-//                    记录前置条件结果
-//                    preData.put("preParameters", params);
-//                    直接结束后续算法
-                    if (Objects.equals("2", preCode)) {
-                        break;
-//                        跳过当前算法
-                    } else if (Objects.equals("1", preCode)) {
-                        resource.add(null);
-                        continue;
-//                        返回不等于0的情况暂时不支持,不处理
-                    } else if (!Objects.equals("0", preCode)) {
-//
-                        throw new RuntimeException("返回类型暂时不支持,不能处理");
-                    }
-                }
-
-                resource.add(data);
-
-                Object algorithmsourcelibraryid = algorithmLibrary.get("algorithmsourcelibraryid");
-//                if (Objects.nonNull(algorithmsourcelibraryid) && !algorithmsourcelibraryid.toString().trim().isEmpty()) {
-
-                List<Map<String, Object>> algorithmsourcelibraryList = DATA_BASE.query(Config.getCenterConnectionStr(), "select * from algorithmsourcelibrary where id=? ", algorithmsourcelibraryid);
-                Map<String, Object> algorithmsourcelibrary = algorithmsourcelibraryList.get(0);
-
-                HashMap<String, Object> configMap = new HashMap<>();
-                Object methodName = algorithmsourcelibrary.get("code");
-                configMap.put("methodName", methodName);
-                configMap.put("path", algorithmsourcelibrary.get("filepath"));
-                Object className = algorithmsourcelibrary.get("library");
-                configMap.put("className", className);
-                Map<String, Object> result;
-                if ("com.scbfkj.uni.library.script.JsScriptEngineUtil".equals(className) && "eval".equals(methodName)) {
-                    String expressionStr = algorithmLibrary.get("computingexpression").toString();
-                    result = JsScriptEngineUtil.eval(expressionStr, resource);
-                } else {
-                    List<Map<String, Object>> params = DATA_BASE.query(Config.getCenterConnectionStr(), """
-                            select
-                            algorithmparametersid, algorithmlibraryid, parametername, subscriptionexpressions, parametertype, datasource
-                            from algorithmparameters where algorithmlibraryid =?""", algorithmlibraryid.toString());
-
-//        获取入参列表
-                    List<Object> parameters = new ArrayList<>();
-                    for (Map<String, Object> param : params) {
-                        Object o = param.get("datasource");
-                        Object subscriptionExpressions = param.get("subscriptionexpressions");
-                        Object parameterType = param.get("parametertype");
-                        if ("0".equals(o)) {
-
-
-                        } else if ("1".equals(o)) {
-                            Object o1 = algorithmLibrary.get(subscriptionExpressions);
-                            switch (parameterType.toString()) {
-                                case "String" -> {
-                                    parameters.add(DataFormatUtil.toString(o1));
-                                }
-                                case "Array" -> {
-                                    parameters.add(DataFormatUtil.toList(o1));
-                                }
-                                case "Map" -> {
-                                    parameters.add(DataFormatUtil.toMap(o1));
-                                }
-                                case "Number" -> {
-                                    parameters.add(NumberFormat.getInstance().parse(o1.toString()));
-                                }
-                                case "Boolean" -> {
-                                    parameters.add(Boolean.parseBoolean(o1.toString()));
-                                }
-                                default -> {
-                                    throw new RuntimeException("参数数据类型错误");
-                                }
-                            }
-
-                        } else if ("2".equals(o)) {
-
-                            switch (parameterType.toString()) {
-                                case "String" -> {
-                                    parameters.add(DataFormatUtil.toString(subscriptionExpressions));
-                                }
-                                case "Array" -> {
-                                    parameters.add(DataFormatUtil.toList(subscriptionExpressions));
-                                }
-                                case "Map" -> {
-                                    parameters.add(DataFormatUtil.toMap(subscriptionExpressions));
-                                }
-                                case "Number" -> {
-                                    parameters.add(NumberFormat.getInstance().parse(subscriptionExpressions.toString()));
-                                }
-                                case "Boolean" -> {
-                                    parameters.add(Boolean.parseBoolean(subscriptionExpressions.toString()));
-                                }
-                                default -> {
-                                    throw new RuntimeException("参数数据类型错误");
-                                }
-                            }
-                        } else if ("3".equals(o)) {
-                            parameters.addAll(getParams(parameterType + ".$.args" + subscriptionExpressions.toString(), source));
-                        }
-
-                    }
-                    data.put("parameters", parameters);
-                    result = JavaScriptEngineUtil.invoke(configMap, methodName.toString(), parameters.toArray());
-                }
-                if ("0".equals(result.get("code"))) {
-                    Object returnData = result.get("returnData");
-                    if (returnData instanceof Map<?, ?> d) {
-                        if (Objects.isNull(result.get("code"))) {
-                            algorithmResult = result;
-                        } else {
-                            algorithmResult = (Map<String, Object>) d;
-                        }
-                    } else {
-                        algorithmResult = result;
-                    }
-                } else {
-                    message = result.get("message").toString();
-                    throw new RuntimeException(message);
-                }
-//                    算法执行结果
-                data.put("result", algorithmResult);
-                execTime = System.currentTimeMillis() - startTime;
-//                    执行时长
-                data.put("execTime", execTime);
-//                    执行成功与否
-                Object code = Optional.ofNullable(algorithmResult.get("code")).map(DataFormatUtil::toString).orElse(null);
-                message = Optional.ofNullable(algorithmResult.get("message")).map(DataFormatUtil::toString).orElse(null);
-                data.put("resultCode", code);
-
-                if (!Objects.equals(code, "0")) {
-                    throw new RuntimeException(message);
-                }
-            }
-            Object data = null;
-            if (!resource.isEmpty()) {
-                data = resource.get(resource.size() - 1);
-
-                if (Objects.nonNull(data)) {
-                    data = ((Map<?, ?>) data).get("result");
-                }
-                if (Objects.nonNull(data)) {
-                    data = ((Map<?, ?>) data).get("returnData");
-                }
-            }
-            return UniReturnUtil.success(data);
-        } catch (Exception e) {
-            message = e.getMessage();
-            if (Config.isDebug()) {
-                e.printStackTrace();
-            }
-            return UniReturnUtil.fail(e);
-        } finally {
-
-//                    不管成功还是失败都记录日志
-            if (serviceInfo != null) {
-                Object enablelog = serviceInfo.get("enablelog");
-                if (Config.isDebug() || Objects.nonNull(serviceInfo) && Objects.equals("1", Objects.nonNull(enablelog) ? enablelog.toString() : null)) {
-                    String finalMessage = message;
-                    LocalDateTime finalStartDateTime = startDateTime;
-                    String finalServiceId = serviceId;
-                    String finalLifecycleid = lifecycleid;
-//                使用线程不阻塞
-                    executor.execute(() -> {
-                        LoggerService.LogType target = LoggerService.LogType.SERVICE;
-                        if (Objects.nonNull(finalMessage)) {
-                            target = LoggerService.LogType.SERVICE_ERR;
-                        }
-                        HashMap<String, Object> logData = new HashMap<>();
-                        logData.put("begintime", finalStartDateTime);
-                        LocalDateTime dateTime = LocalDateTime.now();
-                        logData.put("endtime", dateTime);
-                        logData.put("serviceid", finalServiceId);
-                        String string = DataFormatUtil.toString(resource);
-                        if (Config.isDebug()) {
-                            System.out.println("resources:" + string);
-                        }
-                        logData.put("inputdata", string);
-                        logData.put("prepesource", DataFormatUtil.toString(preResource));
-                        logData.put("returnmessage", finalMessage);
-                        logData.put("lifecycleid", finalLifecycleid);
-                        try {
-                            LoggerService.log(target, logData);
-                        } catch (Exception exception) {
-                            if (Config.isDebug()) {
-                                exception.printStackTrace();
-                            }
-                        }
-                    });
-
-                }
-//                使用线程不阻塞
-            }
-            String finalServiceId1 = serviceId;
-            executor.execute(() -> {
-                try {
-                    DATA_BASE.update(Config.getCenterConnectionStr(), """
-                            update servicestate
-                            set lasttime = ?,workpath = ?
-                            where serviceid=? and containercode=?""", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyy-MM-dd HH:mm:ss")), new File(".").getAbsolutePath(), finalServiceId1, Config.getContainerCode());
-                } catch (Exception e) {
-                    e.printStackTrace();
-                }
-            });
-        }
-
-    }
-
-    /**
-     * 根据算法类型对数据进行处理
-     *
-     * @param type       算法类型
-     * @param parameters 算法参数
-     * @return 处理结果
-     * @throws Exception
-     */
-    public static Map<String, Object> processByAlgorithm(Object type, List<Object> parameters) throws Exception {
-
-        switch (type.toString().toUpperCase()) {
-            // java反射
-            case "1", "JAVA" -> {
-                return JavaScriptEngineUtil.invoke((Map<String, Object>) parameters.get(0), DataFormatUtil.toString(parameters.get(1)), parameters.subList(2, parameters.size()).toArray());
-            }
-            // JS表达式
-//            case "2", "JS" -> {
-//                return JsScriptEngineUtil.eval(DataFormatUtil.toString(parameters.get(0)),);
-//            }
-            // 数据库
-            case "3", "DB" -> {
-                // 下放到Database中处理数据
-                // 参数表达式顺序是 数据源连接字符串(String.$.datasource.connectset),sql表达式(String.$.algorithm.computingexpression),需要操作的值(List.$.args[1].returnData),执行编号(String.$.algorithm.executionnumber)
-                String expression = DataFormatUtil.toString(parameters.get(1));
-                expression = expression.replaceAll("\\s*(\\r)?\\n\\s*", " ").trim();
-                boolean isTableName = !expression.contains(" ");
-                if (isTableName) {
-                    return DATABASE_SCRIPT_UTIL.execByTableName(DataFormatUtil.toString(parameters.get(0)), expression, (Map<String, Object>) parameters.get(2));
-                } else {
-                    return DATABASE_SCRIPT_UTIL.execBySql(DataFormatUtil.toString(parameters.get(0)), expression, (Map<String, Object>) parameters.get(2));
-                }
-            }
-            default -> {
-                return UniReturnUtil.fail("算法类型不支持");
-            }
-        }
-    }
-
-
-    /**
-     * @param parameterSet 使用非标准的jsonPath表达式 String.$.a.b[0].c,String.abcc 多个参数之间使用;;分隔
-     * @param source       jsonpath需要取值的数据源
-     * @return
-     */
-    public List<Object> getParams(String parameterSet, Object source) {
-        List<Object> res;
-        if (Objects.isNull(parameterSet)) {
-            res = Collections.emptyList();
-        } else {
-            String[] paths = parameterSet.split(";;");
-            String json = DataFormatUtil.toString(source);
-            List<Object> result = new ArrayList<>();
-            for (String it : paths) {
-                it = it.trim();
-                String type = it.split("\\.")[0];
-                if (!List.of("string", "list", "map", "array", "long", "integer", "boolean", "double", "float", "datetime").contains(type.toLowerCase())) {
-                    if (Objects.equals("null", type.toLowerCase())) {
-                        result.add(null);
-                    } else {
-                        result.add(type);
-                    }
-                    continue;
-                }
-                String path = it.replace(type + ".", "");
-                Object value = null;
-//            $开头的使用标准的jsonPath
-                if (path.startsWith("$")) {
-                    value = JsonPath.read(json, path);
-                } else if (path.startsWith("#")) {
-//                todo  缓存中的值,获取什么位置的缓存?
-
-//                不是使用$#开头的直接取后面的字符串
-                } else {
-                    value = path;
-                }
-                if (Objects.isNull(value)) {
-                    result.add(null);
-                    continue;
-                }
-                if ("String".equalsIgnoreCase(type)) {
-                    value = DataFormatUtil.toString(value);
-                } else if ("List".equalsIgnoreCase(type)) {
-                    value = DataFormatUtil.toList(value);
-                } else if ("Array".equalsIgnoreCase(type)) {
-                    value = DataFormatUtil.toArray(value);
-                } else if ("Map".equalsIgnoreCase(type)) {
-                    value = DataFormatUtil.toMap(value);
-                } else if ("Long".equalsIgnoreCase(type)) {
-                    value = Long.parseLong(value.toString());
-                } else if ("Integer".equalsIgnoreCase(type)) {
-                    value = Integer.parseInt(value.toString());
-                } else if ("Double".equalsIgnoreCase(type)) {
-                    value = Double.parseDouble(value.toString());
-                } else if ("Float".equalsIgnoreCase(type)) {
-                    value = Float.parseFloat(value.toString());
-                } else if ("Boolean".equalsIgnoreCase(type)) {
-                    value = Boolean.parseBoolean(value.toString());
-                } else if ("Datetime".equalsIgnoreCase(type)) {
-                    String string = value.toString();
-                    String patten = "yyyy-MM-dd HH:mm:ss";
-                    if (string.contains("(")) {
-                        patten = string.substring(string.indexOf("(") + 1, string.length() - 1);
-                        string = string.substring(0, string.indexOf("("));
-                    }
-                    value = LocalDateTime.parse(string, DateTimeFormatter.ofPattern(patten));
-                }
-
-                result.add(value);
-            }
-            res = result;
-        }
-        return res;
-    }
-
-
-}

+ 251 - 150
src/main/java/com/scbfkj/uni/service/LoggerService.java

@@ -6,6 +6,7 @@ import com.scbfkj.uni.process.DataBase;
 import com.scbfkj.uni.process.Elasticsearch;
 import com.scbfkj.uni.process.Kafka;
 import com.scbfkj.uni.system.Config;
+import com.scbfkj.uni.system.ProcessUtil;
 import com.zaxxer.hikari.pool.HikariPool;
 
 import java.io.File;
@@ -16,9 +17,18 @@ import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+
 public class LoggerService {
 
+    /**
+     * 定义数据库实例,用于全局访问。
+     */
     private static final DataBase DATA_BASE = new DataBase();
+
+    /**
+     * 连接配置字符串,采用JSON格式,用于定义数据库连接参数。
+     * 其中%s会被具体文件名替换。
+     */
     private static final String CONNECTION = """
             {
               "jdbcUrl": "jdbc:sqlite:%s",
@@ -26,20 +36,49 @@ public class LoggerService {
               "enableCache":false
             }
             """;
-    private final static Set<Long> fileNames = new HashSet<>();
+
+    /**
+     * 用于存储已经处理过的文件名的集合,避免重复处理。
+     */
+    private static final  Set<Long> fileNames = new HashSet<>();
+
+    /**
+     * 定义日志文件存储目录。
+     */
     private static final String DIR = "logs/";
+
+    /**
+     * 当前处理的文件名。
+     */
     private static String currentFileName;
 
+    /**
+     * 记录日志信息到SQLite数据库。
+     *
+     * @param type 日志类型,决定日志的存储和处理方式。
+     * @param data 日志数据,包含日志的具体内容,可以为null。
+     *
+     * 此方法首先检查日志类型是否为服务类型,并且确保数据非空时,添加容器编码到数据中。
+     * 然后,基于当前时间戳和配置的分隔数生成文件名,并构建对应的数据库连接字符串。
+     * 如果当前日志文件不存在,则创建新的日志表。
+     * 最后,如果提供了日志数据且非空,将数据批量插入到日志表中。
+     */
     public static void log(LogType type, Map<String, Object> data) {
+        // 为服务类型日志添加容器编码
         if ((LogType.SERVICE == type || LogType.SERVICE_ERR == type) && data != null) {
             data.put("containercode", Config.getContainerCode());
         }
+
+        // 根据当前时间生成文件名
         long filename = System.currentTimeMillis() / Config.getSplitCount();
         currentFileName = filename + ".sqlite";
         String filePath = DIR + currentFileName;
         String connectionStr = CONNECTION.formatted(filePath);
+
+        // 确保日志文件列表中只包含当前和之前的日志文件,避免过多历史文件
         synchronized (fileNames) {
             if (!fileNames.contains(filename)) {
+                // 如果日志文件不存在,则创建日志表
                 if (!new File(filePath).exists()) {
                     try {
                         DATA_BASE.exec(connectionStr, """
@@ -58,17 +97,22 @@ public class LoggerService {
                     }
                 }
                 fileNames.add(filename);
+                // 清理过期的文件名
                 fileNames.removeIf(it -> it + 1000 < filename);
             }
+
+            // 如果提供了日志数据,将其批量插入到数据库中
             if (data != null && !data.isEmpty()) {
                 try {
                     List<Object[]> datas = new ArrayList<>();
+                    // 查询系统信息,用于日志的额外标识
                     List<Map<String, Object>> targets = DATA_BASE.query(Config.getCenterConnectionStr(), "select * from systeminfo where keyname=?", type.getName());
                     for (Map<String, Object> targetconnection : targets) {
                         datas.add(new Object[]{type.getName(), filePath, targetconnection.get("datasourceid"), targetconnection.get("expression"), DataFormatUtil.toString(data)});
                     }
                     DATA_BASE.updateBatch(connectionStr, "insert into logs (target,currentfile,datasourceid,expression,datacontent) values(?,?,?,?,?)", datas);
                 } catch (Exception e) {
+                    // 在调试模式下打印异常堆栈
                     if (Config.isDebug()) {
                         e.printStackTrace();
                     }
@@ -77,190 +121,247 @@ public class LoggerService {
         }
     }
 
-    public static void sendMessage() {
-        log(LogType.SYSTEM, null);
-
-//        判断目录
-
-        File file = new File(DIR);
+/**
+ * 发送日志消息。
+ * 该方法首先会筛选出当前不使用的日志文件,然后从这些文件中查询日志数据,并根据目标进行分类,
+ * 分别将日志数据发送到对应的 Kafka、Elasticsearch 或数据库中。
+ * 完成后,会清理已处理的日志文件。
+ */
+public static void sendMessage() {
+    log(LogType.SYSTEM, null);
 
-//        过滤出当前不使用的文件
-        List<File> logsFiles = Arrays.stream(Objects.requireNonNull(file.listFiles())).filter(logFile -> {
-            String fileName = logFile.getName();
-            return !fileName.equals(currentFileName) && fileName.endsWith("sqlite");
-        }).toList();
-//        记录出错的日志文件
-        List<String> errorFileNames = new ArrayList<>();
-        logsFiles.parallelStream().map(logFile -> {
-                    String fileName = logFile.getName();
-//                    转成连接字符串
-                    return CONNECTION.formatted(DIR + fileName);
-                }).flatMap(connectionStr -> {
-//                    查询数据
-                    try {
-                        return DATA_BASE.query(connectionStr, "select logid, target, currentfile, datasourceid, expression, datacontent from logs ").stream();
-                    } catch (Exception e) {
-                        Matcher matcher = Pattern.compile("logs/\\d+\\.sqlite").matcher(connectionStr);
-                        if (matcher.find()) {
-                            errorFileNames.add(matcher.group());
-                        }
-                        return Stream.empty();
-                    } finally {
+    // 判断日志目录是否存在
+    File file = new File(DIR);
 
-                        removeDataSource(connectionStr);
-                    }
+    // 筛选出当前不使用的日志文件
+    List<File> logsFiles = Arrays.stream(Objects.requireNonNull(file.listFiles())).filter(logFile -> {
+        String fileName = logFile.getName();
+        return !fileName.equals(currentFileName) && fileName.endsWith("sqlite");
+    }).toList();
 
+    // 记录处理过程中出现错误的日志文件名
+    List<String> errorFileNames = new ArrayList<>();
+    logsFiles.parallelStream().map(logFile -> {
+        String fileName = logFile.getName();
+        // 构建数据库连接字符串
+        return CONNECTION.formatted(DIR + fileName);
+    }).flatMap(connectionStr -> {
+        // 查询日志数据
+        try {
+            return DATA_BASE.query(connectionStr, "select logid, target, currentfile, datasourceid, expression, datacontent from logs ").stream();
+        } catch (Exception e) {
+            Matcher matcher = Pattern.compile("logs/\\d+\\.sqlite").matcher(connectionStr);
+            if (matcher.find()) {
+                errorFileNames.add(matcher.group());
+            }
+            return Stream.empty();
+        } finally {
+            // 移除数据源连接
+            removeDataSource(connectionStr);
+        }
+    })
+    // 按目标分类日志数据
+    .collect(Collectors.groupingBy((log) -> log.get("target").toString())).entrySet().parallelStream().forEach(stringListEntry -> {
+        String targetName = stringListEntry.getKey();
+        // 按数据源ID分组
+        List<Map<String, Object>> value = stringListEntry.getValue();
+        Map<String, List<Map<String, Object>>> targetconnection = value.stream().collect(Collectors.groupingBy(data -> data.get("datasourceid").toString()));
 
-                })
-//                分组
-                .collect(Collectors.groupingBy((log) -> log.get("target").toString())).entrySet().parallelStream().forEach(stringListEntry -> {
-                    String targetName = stringListEntry.getKey();
-//                    需要发送的数据
-                    List<Map<String, Object>> value = stringListEntry.getValue();
-//                    按照目标连接字符串分组
-                    Map<String, List<Map<String, Object>>> targetconnection = value.stream().collect(Collectors.groupingBy(data -> data.get("datasourceid").toString()));
+        targetconnection.forEach((datasourceid, value1) -> {
+            // 获取发送的数据流
+            Stream<String> datacontentStream = value1.stream().map(data -> data.get("datacontent").toString());
 
-                    targetconnection.forEach((datasourceid, value1) -> {
-//                        获取发送的数据流
-                        Stream<String> datacontentStream = value1.stream().map(data -> data.get("datacontent").toString());
+            // 解析发送目标连接字符串
+            try {
+                List<Map<String, Object>> dataSourceList = DATA_BASE.query(Config.getCenterConnectionStr(), "select   * from datasource where datasourceid=?", datasourceid);
+                if (dataSourceList.isEmpty()) {
+                    return;
+                }
+                Map<String, Object> config = dataSourceList.get(0);
+                String type = config.getOrDefault("datasourcetype", "DB").toString();
+                String connectionStr;
+                List<Object> parameters = new ArrayList<>();
 
-//                        解析发送目标连接字符串
-                        try {
-                            List<Map<String, Object>> dataSourceList = DATA_BASE.query(Config.getCenterConnectionStr(), "select   * from datasource where datasourceid=?", datasourceid);
-                            if (dataSourceList.isEmpty()) {
-                                return;
-                            }
-                            Map<String, Object> config = dataSourceList.get(0);
-                            String type = config.getOrDefault("datasourcetype", "DB").toString();
-                            String connectionStr;
-                            List<Object> parameters = new ArrayList<>();
+                // 根据数据源类型发送数据
+                switch (type.toUpperCase()) {
+                    case "KAFKA" -> {
+                        connectionStr = DataFormatUtil.toString(dataSourceList.stream().findFirst().map(it -> {
+                            HashMap<String, Object> hashMap = new HashMap<>();
+                            hashMap.put("bootstrap.servers", it.get("host"));
+                            return hashMap;
+                        }).get());
+                        List<Object> datas = datacontentStream.map(Object.class::cast).toList();
+                        Kafka.sendMessage(connectionStr, targetName, datas);
+                    }
+                    case "ES" -> {
+                        connectionStr = DataFormatUtil.toString(dataSourceList.stream().findFirst().map(it -> {
+                            HashMap<String, Object> hashMap = new HashMap<>();
+                            hashMap.put("host", it.get("host"));
+                            return hashMap;
+                        }).orElse(new HashMap<>()));
+                        List<String> datas = datacontentStream.toList();
+                        Elasticsearch.exec(connectionStr, targetName, "CREATE", datas);
+                    }
+                    case "DB" -> {
+                        connectionStr = DataFormatUtil.toString(dataSourceList.stream().findFirst().map(it -> {
+                            HashMap<String, Object> hashMap = new HashMap<>();
+                            hashMap.put("jdbcUrl", it.get("host"));
+                            hashMap.put("username", it.get("username"));
+                            hashMap.put("password", it.get("password"));
+                            hashMap.put("driverClassName", it.get("driverclassname"));
+                            return hashMap;
+                        }).orElse(new HashMap<>()));
+                        parameters.add(connectionStr);
+                        parameters.add(targetName);
+                        HashMap<Object, Object> hashMap = new HashMap<>();
+                        hashMap.put("datacontent", datacontentStream.map(DataFormatUtil::toMap).map(dataContent -> ((Map<String, Object>) dataContent)).toList());
+                        hashMap.put("event", "1");
+                        parameters.add(hashMap);
+                        ProcessUtil.processByAlgorithm("3", parameters);
+                    }
+                }
+            } catch (Exception e) {
+                // 记录错误的日志文件名
+                value.stream().findFirst().map(d -> d.get("currentfile").toString()).ifPresent(errorFileNames::add);
+                System.out.println(UniReturnUtil.getMessage(e));
+            }
+        });
+        // 若无错误,从数据库中删除已处理的日志
+        value.stream().findFirst().map(d -> d.get("currentfile").toString()).ifPresent((it) -> {
+            if (!errorFileNames.contains(it)) {
+                String connectionStr = CONNECTION.formatted(it);
+                try {
+                    DATA_BASE.exec(connectionStr, """
+                            delete
+                             from logs
+                             where 1=1""");
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                } finally {
+                    // 移除数据源连接
+                    removeDataSource(connectionStr);
+                }
+            }
+        });
+    });
+    // 清理日志文件和错误的日志文件
+    cleanFile(logsFiles, errorFileNames);
+}
 
-                            switch (type.toUpperCase()) {
-                                case "KAFKA" -> {
-                                    connectionStr = DataFormatUtil.toString(dataSourceList.stream().findFirst().map(it -> {
-                                        HashMap<String, Object> hashMap = new HashMap<>();
-                                        hashMap.put("bootstrap.servers", it.get("host"));
-                                        return hashMap;
-                                    }).get());
-                                    List<Object> datas = datacontentStream.map(Object.class::cast).toList();
-                                    Kafka.sendMessage(connectionStr, targetName, datas);
-                                }
-                                case "ES" -> {
-                                    connectionStr = DataFormatUtil.toString(dataSourceList.stream().findFirst().map(it -> {
-                                        HashMap<String, Object> hashMap = new HashMap<>();
-                                        hashMap.put("host", it.get("host"));
-                                        return hashMap;
-                                    }).get());
-                                    List<String> datas = datacontentStream.toList();
-                                    Elasticsearch.exec(connectionStr, targetName, "CREATE", datas);
-                                }
-                                case "DB" -> {
 
-                                    connectionStr = DataFormatUtil.toString(dataSourceList.stream().findFirst().map(it -> {
-                                        HashMap<String, Object> hashMap = new HashMap<>();
-                                        hashMap.put("jdbcUrl", it.get("host"));
-                                        hashMap.put("username", it.get("username"));
-                                        hashMap.put("password", it.get("password"));
-                                        hashMap.put("driverClassName", it.get("driverclassname"));
-                                        return hashMap;
-                                    }).get());
-                                    parameters.add(connectionStr);
-                                    parameters.add(targetName);
-                                    parameters.add(new HashMap<>() {{
-                                        put("datacontent", datacontentStream.map(DataFormatUtil::toMap).map(dataContent -> ((Map<String, Object>) dataContent)).toList());
-                                        put("event", "1");
-                                    }});
-                                    DataProcessService.processByAlgorithm("3", parameters);
-                                }
-                            }
+/**
+ * 清理日志文件。
+ * 该方法遍历日志文件列表,对于不在错误文件名列表中的文件,尝试进行以下操作:
+ * 1. 更新数据库,删除对应的日志记录。
+ * 2. 关闭与该文件相关的数据库连接池。
+ * 3. 删除文件本身。
+ * 4. 从文件名列表中移除该文件名。
+ *
+ * @param logsFiles 要清理的日志文件列表。
+ * @param errorFileNames 错误文件名列表,这些文件不会被清理。
+ */
+private static void cleanFile(List<File> logsFiles, List<String> errorFileNames) {
+    logsFiles.stream().filter(f -> errorFileNames.stream().filter(Objects::nonNull).noneMatch(errorFileName -> errorFileName.contains(f.getName()))).forEach(f -> {
+        String connectionStr = CONNECTION.formatted(DIR + f.getName());
+        try {
+            // 更新数据库,删除日志记录。
+            DATA_BASE.update(connectionStr, "delete from logs");
 
-                        } catch (Exception e) {
-//                        当前数据是在哪一个数据库文件中
-                            value.stream().findFirst().map(d -> d.get("currentfile").toString()).ifPresent(errorFileNames::add);
-                            System.out.println(UniReturnUtil.getMessage(e));
-                        }
-                    });
-                    value.stream().findFirst().map(d -> d.get("currentfile").toString()).ifPresent((it) -> {
-                        if (!errorFileNames.contains(it)) {
-                            String connectionStr = CONNECTION.formatted(it);
-                            try {
-                                DATA_BASE.exec(connectionStr, """
-                                        delete
-                                         from logs
-                                         where 1=1""");
-                            } catch (Exception e) {
-                                throw new RuntimeException(e);
-                            } finally {
-                                removeDataSource(connectionStr);
-                            }
-                        }
-                    });
-                });
-        cleanFile(logsFiles, errorFileNames);
-    }
+            // 关闭对应的数据库连接池。
+            HikariPool hikariPool = DataBase.getDataSourcePools().remove(connectionStr);
+            if (Objects.nonNull(hikariPool)) hikariPool.shutdown();
 
-    private static void cleanFile(List<File> logsFiles, List<String> errorFileNames) {
-        logsFiles.stream().filter(f -> errorFileNames.stream().filter(Objects::nonNull).noneMatch(errorFileName -> errorFileName.contains(f.getName()))).forEach(f -> {
-            String connectionStr = CONNECTION.formatted(DIR + f.getName());
-            try {
-                DATA_BASE.update(connectionStr, "delete  from logs");
-                HikariPool hikariPool = DataBase.dataSourcePools.remove(connectionStr);
-                if (Objects.nonNull(hikariPool)) hikariPool.shutdown();
-//                删除文件一直不成功 怀疑是数据库连接导致文件被使用导致一直删除不成功
-                f.delete();
-                fileNames.remove(Long.parseLong(f.getName().substring(0, f.getName().indexOf(".sqlite"))));
-            } catch (Exception e) {
-                if (Config.isDebug()) {
-                    e.printStackTrace();
-                } else {
-                    System.out.println(UniReturnUtil.getMessage(e));
-                }
-                if (e instanceof SQLException sqlException) {
-                    if (sqlException.getMessage().contains("no such table: logs")) {
-                        HikariPool hikariPool = DataBase.dataSourcePools.remove(connectionStr);
-                        if (Objects.nonNull(hikariPool)) {
-                            try {
-                                hikariPool.shutdown();
-                            } catch (InterruptedException ex) {
-                                if (Config.isDebug()) {
-                                    ex.printStackTrace();
-                                } else {
-                                    System.out.println(UniReturnUtil.getMessage(ex));
-                                }
+            // 尝试删除文件。
+            f.delete();
+            fileNames.remove(Long.parseLong(f.getName().substring(0, f.getName().indexOf(".sqlite"))));
+        } catch (Exception e) {
+            // 异常处理,根据配置决定是否打印堆栈信息。
+            if (Config.isDebug()) {
+                e.printStackTrace();
+            } else {
+                System.out.println(UniReturnUtil.getMessage(e));
+            }
+            // 处理特定的SQLException。
+            if (e instanceof SQLException sqlException) {
+                // 如果数据库表不存在,则关闭连接池并尝试删除文件。
+                if (sqlException.getMessage().contains("no such table: logs")) {
+                    HikariPool hikariPool = DataBase.getDataSourcePools().remove(connectionStr);
+                    if (Objects.nonNull(hikariPool)) {
+                        try {
+                            hikariPool.shutdown();
+                        } catch (InterruptedException ex) {
+                            // 中断异常处理。
+                            if (Config.isDebug()) {
+                                ex.printStackTrace();
+                            } else {
+                                System.out.println(UniReturnUtil.getMessage(ex));
                             }
                         }
-                        f.delete();
                     }
+                    f.delete();
                 }
-            } finally {
-                removeDataSource(connectionStr);
             }
-        });
-    }
+        } finally {
+            // 确保从数据源列表中移除该连接。
+            removeDataSource(connectionStr);
+        }
+    });
+}
+
 
+    /**
+     * 从数据源池中移除指定的连接字符串,并关闭对应的HikariPool。
+     *
+     * @param connectionStr 连接字符串,用于标识要移除的数据源。
+     */
     private static void removeDataSource(String connectionStr) {
-        HikariPool hikariPool = DataBase.dataSourcePools.remove(connectionStr);
+        // 从数据源池中移除指定连接字符串,并尝试关闭对应的HikariPool
+        HikariPool hikariPool = DataBase.getDataSourcePools().remove(connectionStr);
         if (Objects.nonNull(hikariPool)) {
             try {
-                hikariPool.shutdown();
+                hikariPool.shutdown(); // 关闭HikariPool
             } catch (InterruptedException e) {
+                // 当关闭操作被中断时,根据配置决定是否打印堆栈信息
                 if (Config.isDebug()) {
                     e.printStackTrace();
                 }
             }
         }
     }
-
+    /**
+     * 日志类型枚举,定义了不同种类的日志。
+     * 枚举值与日志名称映射,用于标识和区分不同的日志类型。
+     */
     public enum LogType {
 
-        USER("userlog"), INTERFACE("interfacelog"), SYSTEM("systemerrlog"), SERVICE("servicelog"), SERVICE_ERR("serviceerrlog"), QUALITY_CONTROL("qualitycontrollog");
+        // 用户操作日志
+        USER("userlog"),
+        // 接口调用日志
+        INTERFACE("interfacelog"),
+        // 系统错误日志
+        SYSTEM("systemerrlog"),
+        // 服务日志
+        SERVICE("servicelog"),
+        // 服务错误日志
+        SERVICE_ERR("serviceerrlog"),
+        // 质量控制日志
+        QUALITY_CONTROL("qualitycontrollog");
 
+        // 日志名称
         private final String name;
 
+        /**
+         * 构造函数,用于初始化枚举值和其对应的名称。
+         * @param name 日志类型的名称。
+         */
         LogType(String name) {
             this.name = name;
         }
 
+        /**
+         * 获取日志类型的名称。
+         * @return 返回该日志类型的名称字符串。
+         */
         public String getName() {
             return name;
         }

+ 448 - 258
src/main/java/com/scbfkj/uni/service/SecurityService.java

@@ -24,9 +24,18 @@ public class SecurityService {
     @Value("${app.debug:false}")
     private boolean debug;
 
+    /**
+     * 创建指定长度的验证码。
+     *
+     * @param size 验证码的长度。
+     * @param source 用于生成验证码的字符源。
+     * @return 生成的验证码字符串。
+     */
     private static String createCode(int size, String source) {
+        // 初始化一个StringBuilder,用于构建验证码
         StringBuilder verifyCode = new StringBuilder(size);
         int codesLen = source.length();
+        // 循环,向verifyCode中添加随机字符,直到达到指定的size
         for (int i = 0; i < size; i++) {
             verifyCode.append(source.charAt(RANDOM.nextInt(codesLen - 1)));
         }
@@ -37,104 +46,144 @@ public class SecurityService {
     //安全类服务
     //连接认证--获取连接令牌
 
-    public Map<String, Object> getToken(Map<String, Object> requestData) throws Exception {
-        Optional<String> appid = getValue("appid", requestData);
-        Optional<String> appSecret = getValue("appsecret", requestData);
-        if (appSecret.isPresent() && appid.isPresent()) {
-            String clean = "delete from appconnectlog where expiretime < ? ";
-            DATABASE.update(Config.getSecurityConnectionStr(), clean, LocalDateTime.now());
-            String query = """
-                                select applicationid,
-                           appid,
-                           appsecret,
-                           appname,
-                           appengname,
-                           appdescribe,
-                           applogo,
-                           smalllogo,
-                           backgroundimage,
-                           apptokeneffective,
-                           securitycoderule,
-                           securitycodeeffective,
-                           multilogin,
-                           passwordrule,
-                           passwordeffective
-                    from application
-                     where appid = ? and appsecret = ?""";
-            List<Map<String, Object>> applicationList = DATABASE.query(Config.getSecurityConnectionStr(), query, appid.get(), appSecret.get());
-
-            if (applicationList.isEmpty()) {
-                throw new RuntimeException("appid 或 appsecret 错误");
-            }
-            Map<String, Object> application = applicationList.get(0);
+/**
+ * 获取应用令牌。
+ *
+ * @param requestData 包含appid和appsecret等请求数据的Map
+ * @return 返回一个包含令牌信息的Map,如果appid或appsecret为空,则返回失败结果
+ * @throws Exception 如果查询数据库时发生错误,则抛出异常
+ */
+public Map<String, Object> getToken(Map<String, Object> requestData) throws Exception {
+    // 从请求数据中获取appid和appsecret
+    Optional<String> appid = getValue("appid", requestData);
+    Optional<String> appSecret = getValue("appsecret", requestData);
+    // 检查appid和appsecret是否存在
+    if (appSecret.isPresent() && appid.isPresent()) {
+        // 删除过期的连接日志
+        String clean = "delete from appconnectlog where expiretime < ? ";
+        DATABASE.update(Config.getSecurityConnectionStr(), clean, LocalDateTime.now());
+
+        // 查询应用信息
+        String query = """
+                        select applicationid,
+                               appid,
+                               appsecret,
+                               appname,
+                               appengname,
+                               appdescribe,
+                               applogo,
+                               smalllogo,
+                               backgroundimage,
+                               apptokeneffective,
+                               securitycoderule,
+                               securitycodeeffective,
+                               multilogin,
+                               passwordrule,
+                               passwordeffective
+                        from application
+                         where appid = ? and appsecret = ?""";
+        List<Map<String, Object>> applicationList = DATABASE.query(Config.getSecurityConnectionStr(), query, appid.get(), appSecret.get());
+
+        // 如果查询结果为空,抛出运行时异常
+        if (applicationList.isEmpty()) {
+            throw new RuntimeException("appid 或 appsecret 错误");
+        }
+        Map<String, Object> application = applicationList.get(0);
 
+        // 处理应用令牌的有效时间
+        Object apptokeneffectiveObj = application.get("apptokeneffective");
+        Long apptokeneffective = defaultAppTokenEffective;
+        if (Objects.nonNull(apptokeneffectiveObj)) {
+            apptokeneffective = Long.parseLong(apptokeneffectiveObj.toString());
+        }
+        LocalDateTime expiresTime = LocalDateTime.now().plusSeconds(apptokeneffective);
 
-            Object apptokeneffectiveObj = application.get("apptokeneffective");
-            Long apptokeneffective = defaultAppTokenEffective;
-            if (Objects.nonNull(apptokeneffectiveObj)) {
-                apptokeneffective = Long.parseLong(apptokeneffectiveObj.toString());
-            }
-            LocalDateTime expiresTime = LocalDateTime.now().plusSeconds(apptokeneffective);
-            String ip = RequestUtil.getIpAddr();
-            List<Map<String, Object>> logs = DATABASE.query(Config.getSecurityConnectionStr(), "select connid,  apptoken, expiretime, lasttime from appconnectlog where requestip=? and appid = ?", ip, appid.get());
-            String appToken;
-            if (!logs.isEmpty()) {
-                Map<String, Object> applicationlog = logs.get(0);
-                DATABASE.update(Config.getSecurityConnectionStr(), """
-                                                update appconnectlog
-                        set expiretime = ?,lasttime=?
-                        where connid=?""", expiresTime, LocalDateTime.now(), applicationlog.get("connid"));
-                appToken = applicationlog.get("apptoken").toString();
-            } else {
-                String sessionId = RequestUtil.getSessionId();
-                appToken = DataEncryptionUtil.signatureMD5("%s:%s".formatted(LocalDateTime.now(), sessionId));
+        // 获取请求IP地址,并查询连接日志
+        String ip = RequestUtil.getIpAddr();
+        List<Map<String, Object>> logs = DATABASE.query(Config.getSecurityConnectionStr(), "select connid,  apptoken, expiretime, lasttime from appconnectlog where requestip=? and appid = ?", ip, appid.get());
+
+        String appToken;
+        // 如果存在连接日志,则更新并使用现有的令牌;否则,创建新令牌
+        if (!logs.isEmpty()) {
+            Map<String, Object> applicationlog = logs.get(0);
+            DATABASE.update(Config.getSecurityConnectionStr(), """
+                                    update appconnectlog
+                            set expiretime = ?,lasttime=?
+                            where connid=?""", expiresTime, LocalDateTime.now(), applicationlog.get("connid"));
+            appToken = applicationlog.get("apptoken").toString();
+        } else {
+            String sessionId = RequestUtil.getSessionId();
+            appToken = DataEncryptionUtil.signatureMD5("%s:%s".formatted(LocalDateTime.now(), sessionId));
 
-                DATABASE.update(Config.getSecurityConnectionStr(), """
-                                                insert into appconnectlog (appid, requesttime, requestip, apptoken, expiretime, lasttime)
-                        values (?,?,?,?,?,?)""", appid.get(), LocalDateTime.now(), ip, appToken, expiresTime, LocalDateTime.now());
-            }
-//            添加token和过期时间
-            application.put("token", appToken);
-            application.put("expirestime", DataFormatUtil.toString(expiresTime));
+            DATABASE.update(Config.getSecurityConnectionStr(), """
+                                    insert into appconnectlog (appid, requesttime, requestip, apptoken, expiretime, lasttime)
+                            values (?,?,?,?,?,?)""", appid.get(), LocalDateTime.now(), ip, appToken, expiresTime, LocalDateTime.now());
+        }
 
-//            清理敏感信息 appsecret
-            application.put("appsecret", null);
+        // 添加token和过期时间到应用信息,并移除appsecret
+        application.put("token", appToken);
+        application.put("expirestime", DataFormatUtil.toString(expiresTime));
+        application.put("appsecret", null);
 
-            long currentTimeMillis = System.currentTimeMillis();
-            long l = currentTimeMillis << 4;
+        // 生成并添加session ID到应用信息和缓存中
+        long currentTimeMillis = System.currentTimeMillis();
+        long l = currentTimeMillis << 4;
 
-            String string = DataEncryptionUtil.signatureMD5(String.valueOf(l));
-            application.put("sessionid", string);
-            Map<String, Object> sessionMap = Config.cache.computeIfAbsent(string, k -> new Hashtable<>());
-            sessionMap.put("application", application);
-            return UniReturnUtil.success(application);
-        }
-        return UniReturnUtil.fail("appid 或 appsecret 不能为空");
+        String string = DataEncryptionUtil.signatureMD5(String.valueOf(l));
+        application.put("sessionid", string);
+        Map<String, Object> sessionMap = Config.CACHE.computeIfAbsent(string, k -> new Hashtable<>());
+        sessionMap.put("application", application);
+
+        // 返回成功结果,包含应用信息
+        return UniReturnUtil.success(application);
     }
+    // 如果appid或appsecret为空,返回失败结果
+    return UniReturnUtil.fail("appid 或 appsecret 不能为空");
+}
+
 
 
     //刷新连接令牌
 
+    /**
+     * 刷新令牌。
+     * 该方法用于通过当前的应用令牌(appToken)来刷新其过期时间。
+     * 方法会首先尝试更新数据库中的对应令牌的过期时间,如果更新成功,则返回新的过期时间和令牌;
+     * 如果更新失败或出现异常,则返回失败信息。
+     *
+     * @return Map<String, Object> 包含刷新结果的数据映射。成功时包含"expirestime"和"token"键值对;
+     *         失败时返回包含错误信息的映射。
+     * @throws Exception 如果数据库操作出现异常,则抛出异常。
+     */
     public Map<String, Object> refreshToken() throws Exception {
 
+        // 获取应用ID
         Object appid = RequestUtil.getAppId();
 
-
+        // 获取应用信息
         Map<String, Object> application = RequestUtil.getApplication();
 
+        // 默认的app token有效时间
         Long apptokeneffective = defaultAppTokenEffective;
+        // 尝试从应用信息中解析app token有效时间,如果存在则使用
         Object apptokeneffectiveObj = application.get("apptokeneffective");
 
         if (Objects.nonNull(apptokeneffectiveObj)) {
             apptokeneffective = Long.parseLong(apptokeneffectiveObj.toString());
         }
+        // 计算令牌过期时间
         LocalDateTime expiresTime = LocalDateTime.now().plusSeconds(apptokeneffective);
+        // 获取当前应用令牌
         Object appToken = RequestUtil.getAppToken();
+        // 准备返回的数据映射
         Map<String, Object> data = new HashMap<>();
         try {
+            // 构造更新数据库语句,尝试更新appconnectlog表中的过期时间
             String update = "update appconnectlog set expiretime=? where apptoken =? and requestip =? and appid=?";
+            // 执行更新操作
             int updateRow = DATABASE.update(Config.getSecurityConnectionStr(), update, expiresTime, appToken, RequestUtil.getIpAddr(), appid);
 
+            // 判断更新结果,成功则返回刷新后的数据,失败则返回错误信息
             if (updateRow > 0) {
                 data.put("expirestime", DataFormatUtil.toString(expiresTime));
                 data.put("token", appToken);
@@ -143,196 +192,234 @@ public class SecurityService {
                 return UniReturnUtil.fail("刷新令牌失败");
             }
         } catch (Exception exception) {
+            // 捕获异常,返回失败信息附带异常消息
             return UniReturnUtil.fail("刷新令牌失败:%s".formatted(exception.getMessage()));
         }
     }
 
     //获取登录验证码
 
-    public Map<String, Object> getSecurityCode() throws Exception {
+/**
+ * 生成并返回安全码的相关信息。
+ * 该安全码根据应用程序的配置规则生成,可以包含数字、大写字母、小写字母。
+ * 规则通过字符串表示,如"N"代表只包含数字,"W"代表包含大小写字母等。
+ * 安全码的有效期和应用ID等信息也会一并返回。
+ *
+ * @return 一个包含安全码图像(base64编码)和相关配置信息的Map对象。如果未配置安全码规则,返回失败信息。
+ * @throws Exception 如果过程中出现错误,则抛出异常。
+ */
+public Map<String, Object> getSecurityCode() throws Exception {
+
+    // 获取应用ID和应用配置
+    String appId = RequestUtil.getAppId();
+    Map<String, Object> application = RequestUtil.getApplication();
+    Object securityCodeRule = application.get("securitycoderule");
+    Object securityCodeEffectiveObj = application.get("securitycodeeffective");
+    if (Objects.nonNull(securityCodeRule)) {
+        String rule = "";
+        String codeRule = (String) securityCodeRule;
+
+        // 根据规则确定生成安全码的字符集
+        if (codeRule.contains("N")) {
+            rule += "23456789";
+        }
+        if (codeRule.contains("W")) {
+            rule += "ABCDEFGHGKMNPQRSTUVWXYZ";
+            rule += "abcdefghgkmnpqrstuvwxyz";
+        } else if (codeRule.contains("U")) {
+            rule += "ABCDEFGHGKMNPQRSTUVWXYZ";
+        } else if (codeRule.contains("L")) {
+            rule += "abcdefghgkmnpqrstuvwxyz";
+        }
 
-        String appId = RequestUtil.getAppId();
-        Map<String, Object> application = RequestUtil.getApplication();
-        Object securityCodeRule = application.get("securitycoderule");
-        Object securityCodeEffectiveObj = application.get("securitycodeeffective");
-        if (Objects.nonNull(securityCodeRule)) {
-            String rule = "";
-            String codeRule = (String) securityCodeRule;
-//                数字
-            if (codeRule.contains("N")) {
-                rule += "23456789";
-            }
-//            大小写字母 world
-            if (codeRule.contains("W")) {
-                rule += "ABCDEFGHGKMNPQRSTUVWXYZ";
-                rule += "abcdefghgkmnpqrstuvwxyz";
-//                大写字母 upperCase
-            } else if (codeRule.contains("U")) {
-                rule += "ABCDEFGHGKMNPQRSTUVWXYZ";
-//                小写字母 lower
-            } else if (codeRule.contains("L")) {
-                rule += "abcdefghgkmnpqrstuvwxyz";
-            }
-//            最后四位长度为最小长度和最大长度
-            String minMax = codeRule.substring(codeRule.length() - 4);
-
-            Integer min = Integer.parseInt(minMax.substring(0, 2));
-            Integer max = Integer.parseInt(minMax.substring(2));
-
-            Integer length = min;
-            if (!Objects.equals(min, max)) {
-                Random random = new Random();
-                do {
-                    length = random.nextInt(max);
-                } while (length <= min);
-            }
-            String code = createCode(length, rule);
-            String base64Code = ImageUtil.stringToImage(code);
-            String sessionId = RequestUtil.getSessionId();
-            String ip = RequestUtil.getIpAddr();
-            Long securityCodeEffective = defaultSecurityCodeEffective;
-            if (Objects.nonNull(securityCodeEffectiveObj)) {
-                securityCodeEffective = Long.parseLong(securityCodeEffectiveObj.toString());
-            }
-            addCode(code, sessionId, appId, securityCodeEffective, ip);
+        // 解析并确定安全码的长度
+        String minMax = codeRule.substring(codeRule.length() - 4);
+        Integer min = Integer.parseInt(minMax.substring(0, 2));
+        Integer max = Integer.parseInt(minMax.substring(2));
+        Integer length = min;
+        if (!Objects.equals(min, max)) {
+            Random random = new Random();
+            do {
+                length = random.nextInt(max);
+            } while (length <= min);
+        }
 
-            Map<String, Object> data = new HashMap<>();
-            data.put("verifyCodeImage", base64Code);
-            if (Config.isDebug()) {
-                data.put("code", code);
-            }
-            return UniReturnUtil.success(data);
+        // 生成安全码并转换为图像
+        String code = createCode(length, rule);
+        String base64Code = ImageUtil.stringToImage(code);
+        String sessionId = RequestUtil.getSessionId();
+        String ip = RequestUtil.getIpAddr();
+        Long securityCodeEffective = defaultSecurityCodeEffective;
+        if (Objects.nonNull(securityCodeEffectiveObj)) {
+            securityCodeEffective = Long.parseLong(securityCodeEffectiveObj.toString());
         }
-        return UniReturnUtil.fail("没有配置验证码规则");
-    }
 
+        // 将安全码与会话、应用ID等信息关联存储
+        addCode(code, sessionId, appId, securityCodeEffective, ip);
 
-    //用户登录
+        // 准备返回的数据,包含安全码图像和可能的调试信息
+        Map<String, Object> data = new HashMap<>();
+        data.put("verifyCodeImage", base64Code);
+        if (Config.isDebug()) {
+            data.put("code", code);
+        }
+        return UniReturnUtil.success(data);
+    }
+    return UniReturnUtil.fail("没有配置验证码规则");
+}
 
-    public Map<String, Object> login(Map<String, Object> requestData) throws Exception {
 
-        Optional<String> username = getValue("account", requestData);
-        Optional<String> password = getValue("password", requestData);
-        Optional<String> verifycode = getValue("verifycode", requestData);
 
-        String appId = RequestUtil.getAppId();
-        String sessionId = RequestUtil.getSessionId();
-        String ip = RequestUtil.getIpAddr();
-//        解密验证码
-        Map<String, Object> application = RequestUtil.getApplication();
-        Object securityCodeRule = application.get("securitycoderule");
-        String code = null;
+    //用户登录
 
-        if (Objects.nonNull(securityCodeRule) && !debug) {
-            code = DataEncryptionUtil.decryptRSAByPrivateKey(verifycode.get());
-            if (!check(code, sessionId, appId, ip)) {
-                return UniReturnUtil.fail("验证码错误");
-            }
+/**
+ * 登录逻辑处理
+ *
+ * @param requestData 包含登录所需信息的Map,如账号、密码、验证码等
+ * @return 登录结果,成功返回包含用户信息和登录状态的Map,失败返回包含错误信息的Map
+ * @throws Exception 处理过程中可能抛出的异常,如数据解密失败、数据库操作失败等
+ */
+public Map<String, Object> login(Map<String, Object> requestData) throws Exception {
+
+    // 从请求数据中提取用户名、密码、验证码
+    Optional<String> username = getValue("account", requestData);
+    Optional<String> password = getValue("password", requestData);
+    Optional<String> verifycode = getValue("verifycode", requestData);
+
+    // 获取应用ID、会话ID、用户IP等信息
+    String appId = RequestUtil.getAppId();
+    String sessionId = RequestUtil.getSessionId();
+    String ip = RequestUtil.getIpAddr();
+
+    // 解密验证码,并校验其有效性
+    Map<String, Object> application = RequestUtil.getApplication();
+    Object securityCodeRule = application.get("securitycoderule");
+    String code = null;
+
+    if (Objects.nonNull(securityCodeRule) && !debug) {
+        code = DataEncryptionUtil.decryptRSAByPrivateKey(verifycode.get());
+        if (!check(code, sessionId, appId, ip)) {
+            return UniReturnUtil.fail("验证码错误");
         }
+    }
 
-        String loginPassword = DataEncryptionUtil.decryptRSAByPrivateKey(password.get());
-        String query = """
-                select userid,
-                       usergroupid,
-                       username,
-                       account,
-                       userpassword,
-                       userdescribe,
-                       isenable,
-                       secondarypassword,
-                       multilogin,
-                       passwordlastmodified,
-                       isdelete
-                from userinfo
-                     where  account =?""";
-        List<Map<String, Object>> userInfoList = DATABASE.query(Config.getSecurityConnectionStr(), query, username.get());
-
-        Map<String, Object> userInfo;
-        if (userInfoList.isEmpty()) {
-            return UniReturnUtil.fail("用户名密码错误");
-        } else {
-            userInfo = userInfoList.get(0);
-            String userPassword = DataFormatUtil.toString(userInfo.get("userpassword"));
-            try {
-                userPassword = DataEncryptionUtil.decryptRSAByPrivateKey(userPassword);
-            } catch (Exception e) {
-                return UniReturnUtil.fail("密码错误");
-            }
-            if (!Objects.equals(userPassword, loginPassword)) {
-                return UniReturnUtil.fail("用户名密码错误");
-            }
+    // 解密密码
+    String loginPassword = DataEncryptionUtil.decryptRSAByPrivateKey(password.get());
+
+    // 查询数据库验证用户账号和密码
+    String query = """
+            select userid,
+                   usergroupid,
+                   username,
+                   account,
+                   userpassword,
+                   userdescribe,
+                   isenable,
+                   secondarypassword,
+                   multilogin,
+                   passwordlastmodified,
+                   isdelete
+            from userinfo
+                 where  account =?""";
+    List<Map<String, Object>> userInfoList = DATABASE.query(Config.getSecurityConnectionStr(), query, username.get());
+
+    Map<String, Object> userInfo;
+    if (userInfoList.isEmpty()) {
+        return UniReturnUtil.fail("用户名密码错误");
+    } else {
+        userInfo = userInfoList.get(0);
+        String userPassword = DataFormatUtil.toString(userInfo.get("userpassword"));
+        try {
+            userPassword = DataEncryptionUtil.decryptRSAByPrivateKey(userPassword);
+        } catch (Exception e) {
+            return UniReturnUtil.fail("密码错误");
         }
-        Object userId = userInfo.get("userid");
-
-        Map<String, Object> sessionMap = Config.cache.get(sessionId);
-        if (sessionMap == null) {
-            sessionMap = new Hashtable<>();
-            Config.cache.put(sessionId, sessionMap);
+        if (!Objects.equals(userPassword, loginPassword)) {
+            return UniReturnUtil.fail("用户名密码错误");
         }
-        sessionMap.put("userinfo", userInfo);
-        String query1 = """
-                select loginid,
-                       userid,
-                       requestip,
-                       sessionid,
-                       logintime,
-                       usertoken,
-                       lasttime,
-                       lastheartbeat,
-                       logouttime,
-                       apptoken,
-                       isexpires,
-                       appid
-                from userloginlog                 
-                    where userid = ? and isexpires = 0 and logouttime is null""";
-        List<Map<String, Object>> userLoginLogList = DATABASE.query(Config.getSecurityConnectionStr(), query1, userInfo.get("userid"));
+    }
+    Object userId = userInfo.get("userid");
 
-        Map<String, Object> data = new HashMap<>();
-        String appToken = RequestUtil.getAppToken();
-        String insert = "insert into userloginlog ( userid, requestip, sessionid, logintime, usertoken, lasttime, lastheartbeat,apptoken,isexpires,appid)values (?,?,?,?,?,?,?,?,0,?)";
-        if (userLoginLogList.isEmpty()) {
+    // 检查并更新会话信息
+    Map<String, Object> sessionMap = Config.CACHE.get(sessionId);
+    if (sessionMap == null) {
+        sessionMap = new Hashtable<>();
+        Config.CACHE.put(sessionId, sessionMap);
+    }
+    sessionMap.put("userinfo", userInfo);
+
+    // 处理用户登录日志
+    String query1 = """
+            select loginid,
+                   userid,
+                   requestip,
+                   sessionid,
+                   logintime,
+                   usertoken,
+                   lasttime,
+                   lastheartbeat,
+                   logouttime,
+                   apptoken,
+                   isexpires,
+                   appid
+            from userloginlog                 
+                where userid = ? and isexpires = 0 and logouttime is null""";
+    List<Map<String, Object>> userLoginLogList = DATABASE.query(Config.getSecurityConnectionStr(), query1, userInfo.get("userid"));
+
+    Map<String, Object> data = new HashMap<>();
+    String appToken = RequestUtil.getAppToken();
+    String insert = "insert into userloginlog ( userid, requestip, sessionid, logintime, usertoken, lasttime, lastheartbeat,apptoken,isexpires,appid)values (?,?,?,?,?,?,?,?,0,?)";
+
+    // 根据登录日志处理逻辑,更新或插入新的登录日志
+    if (userLoginLogList.isEmpty()) {
+        data.put("userstatus", "0");
+        DATABASE.update(Config.getSecurityConnectionStr(), insert, userId, ip, sessionId, LocalDateTime.now(), null, LocalDateTime.now(), LocalDateTime.now(), appToken, appId);
+    } else {
+        Object multilogin = application.get("multilogin");
+        if (Objects.equals(DataFormatUtil.toString(multilogin), "1")) {
+            Optional<Map<String, Object>> log = userLoginLogList.stream().filter(it -> it.get("sessionid").equals(sessionId)).findAny();
+            if (log.isEmpty()) {
+                DATABASE.update(Config.getSecurityConnectionStr(), insert, userId, ip, sessionId, LocalDateTime.now(), null, LocalDateTime.now(), LocalDateTime.now(), appToken, appId);
+            }
             data.put("userstatus", "0");
-            DATABASE.update(Config.getSecurityConnectionStr(), insert, userId, ip, sessionId, LocalDateTime.now(), null, LocalDateTime.now(), LocalDateTime.now(), appToken, appId);
-        } else {
-            Object multilogin = application.get("multilogin");
-            if (Objects.equals(DataFormatUtil.toString(multilogin), "1")) {
-                Optional<Map<String, Object>> log = userLoginLogList.stream().filter(it -> it.get("sessionid").equals(sessionId)).findAny();
-                if (log.isEmpty()) {
-                    DATABASE.update(Config.getSecurityConnectionStr(), insert, userId, ip, sessionId, LocalDateTime.now(), null, LocalDateTime.now(), LocalDateTime.now(), appToken, appId);
-//                } else {
-//                    Map<String, Object> map = log.get();
-//                    if (Objects.isNull(map.get("apptoken"))) {
-//
-//                        DataBase.update(Config.getSecurityConnectionStr(), "update  userloginlog set apptoken = ? where loginid = ?", appToken, map.get("loginid"));
-//                    }
-                }
-                data.put("userstatus", "0");
 
-            } else {
-                Optional<Map<String, Object>> log = userLoginLogList.stream().filter(it -> it.get("sessionid").equals(sessionId)).findAny();
-                if (log.isEmpty()) {
+        } else {
+            Optional<Map<String, Object>> log = userLoginLogList.stream().filter(it -> it.get("sessionid").equals(sessionId)).findAny();
+            if (log.isEmpty()) {
 
-                    DATABASE.update(Config.getSecurityConnectionStr(), insert, userId, ip, sessionId, LocalDateTime.now(), null, LocalDateTime.now(), LocalDateTime.now(), appToken, appId);
-                }
-                data.put("userstatus", "1");
+                DATABASE.update(Config.getSecurityConnectionStr(), insert, userId, ip, sessionId, LocalDateTime.now(), null, LocalDateTime.now(), LocalDateTime.now(), appToken, appId);
             }
+            data.put("userstatus", "1");
         }
-        data.put("userid", userId);
-
-        return UniReturnUtil.success(data);
     }
+    // 登录成功,返回用户信息
+    data.put("userid", userId);
+
+    return UniReturnUtil.success(data);
+}
+
 
 
     //强制登录
 
+    /**
+     * 强制登录函数。
+     * 该函数会根据当前的session信息,验证并更新登录状态,返回新的用户令牌(usertoken)。
+     *
+     * @return 返回一个包含登录状态和新用户令牌的Map。如果登录失败,则返回包含错误信息的Map。
+     * @throws Exception 如果发生错误,例如数据库操作失败,则抛出异常。
+     */
     public Map<String, Object> forceLogin() throws Exception {
 
+        // 获取应用令牌、IP地址和session ID
         String appToken = RequestUtil.getAppToken();
         String ip = RequestUtil.getIpAddr();
         String sessionId = RequestUtil.getSessionId();
+        // 验证session ID的有效性
         if (sessionId == null) {
             return UniReturnUtil.fail("sessionid 不匹配");
         }
+        // 构造查询当前登录状态的SQL语句
         String query = """
                 select loginid,
                        userid,
@@ -348,22 +435,39 @@ public class SecurityService {
                        appid
                 from userloginlog
                      where apptoken=? and sessionid=? and requestip=? and isexpires=0 and logouttime is null """;
+        // 执行查询,验证登录状态是否存在
         List<Map<String, Object>> userLoginLogList = DATABASE.query(Config.getSecurityConnectionStr(), query, appToken, sessionId, ip);
+        // 处理查询结果为空的情况,即登录状态不存在
         if (userLoginLogList.isEmpty()) {
             return UniReturnUtil.fail("登录失败:在数据库中没有找到当前session的登录请求");
         }
+        // 取得第一条登录记录
         Map<String, Object> userLoginLog = userLoginLogList.get(0);
+        // 生成新的用户令牌
         String userToken = DataEncryptionUtil.signatureMD5("%s:%s".formatted(LocalDateTime.now(), sessionId));
+        // 更新登录记录,设置新的用户令牌和更新时间
         String update = "update userloginlog set apptoken=null,usertoken=?,lasttime=? where  loginid=?";
         DATABASE.update(Config.getSecurityConnectionStr(), update, userToken, LocalDateTime.now(), userLoginLog.get("loginid"));
+        // 准备返回的数据,包含新的用户令牌
         HashMap<String, Object> data = new HashMap<>();
         data.put("usertoken", userToken);
 
+        // 返回登录成功信息,包含新的用户令牌
         return UniReturnUtil.success(data);
     }
 
+    /**
+     * 根据用户token检查用户登录状态。
+     *
+     * @param userToken 用户的登录token。
+     * @return 返回一个包含登录状态信息的Map。如果登录状态有效,返回一个空的success Map;如果登录状态无效,返回一个包含错误信息的fail Map。
+     * @throws Exception 抛出异常,处理数据库操作错误等情况。
+     */
     public Map<String, Object> checkUserToken(String userToken) throws Exception {
+        // 获取当前请求的session ID
         String sessionId = RequestUtil.getSessionId();
+
+        // 构造查询当前用户token和session ID对应的登录信息的SQL语句
         String query = """
                 select loginid,
                        userid,
@@ -378,35 +482,37 @@ public class SecurityService {
                        isexpires,
                        appid
                 from userloginlog
-                                 where logouttime is null and usertoken = ? and sessionid = ?""";
+                             where logouttime is null and usertoken = ? and sessionid = ?""";
+
+        // 执行查询操作,获取用户登录日志列表
         List<Map<String, Object>> userLoginLogList = DATABASE.query(Config.getSecurityConnectionStr(), query, userToken, sessionId);
+
+        // 如果查询结果不为空,表示用户登录状态有效,返回成功信息
         if (!userLoginLogList.isEmpty()) {
             return UniReturnUtil.success(null);
         }
-//        Map<String, Object> userLoginLog = userLoginLogList.get(0);
-//        Object lastheartbeat = userLoginLog.get("lastheartbeat");
-//        LocalDateTime dateTime = DataFormatUtil.toDateTime(lastheartbeat);
-//        if (Objects.nonNull(dateTime)) {
-//            Map<String, Object> application = RequestUtil.getApplication();
-//            Object apptokeneffectiveObj = application.get("apptokeneffective");
-//            Long apptokeneffective = defaultAppTokenEffective;
-//            if (Objects.nonNull(apptokeneffectiveObj)) {
-//                apptokeneffective = Long.parseLong(apptokeneffectiveObj.toString());
-//            }
-//
-//            if (dateTime.plusSeconds(apptokeneffective).isAfter(LocalDateTime.now())) {
-//                return UniReturnUtil.success(null);
-//            }
-//        }
+
+        // 如果查询结果为空,表示用户登录状态无效,返回失败信息
         return UniReturnUtil.fail("用户token已过期");
 
     }
 
     //用户登出
 
+    /**
+     * 用户登出操作。
+     * 该方法首先会校验用户token和session ID,然后在用户登录日志表中更新登出时间,
+     * 并从缓存中移除对应的session ID。如果登录日志不存在,则认为登出失败。
+     *
+     * @return 返回一个Map对象,包含操作结果信息。成功则包含成功信息,失败则包含失败原因。
+     * @throws Exception 抛出异常的情况未明确指定,可能由数据库操作或其他异常引起。
+     */
     public Map<String, Object> logOut() throws Exception {
+        // 获取用户token和session ID
         String userToken = RequestUtil.getUserToken();
         String sessionId = RequestUtil.getSessionId();
+
+        // 构造查询当前未登出用户的SQL语句
         String query = """
                 select loginid,
                        userid,
@@ -421,35 +527,57 @@ public class SecurityService {
                        isexpires,
                        appid
                 from userloginlog
-                                 where logouttime is null and usertoken=? and sessionid=?""";
+                             where logouttime is null and usertoken=? and sessionid=?""";
 
+        // 根据用户token和session ID查询登录日志
         List<Map<String, Object>> userLoginLogList = DATABASE.query(Config.getSecurityConnectionStr(), query, userToken, sessionId);
 
+        // 如果查询结果为空,表示用户未登录,返回登出失败
         if (userLoginLogList.isEmpty()) {
             return UniReturnUtil.fail("登出失败");
         }
+
+        // 获取登录日志的详细信息
         Map<String, Object> userLoginLog = userLoginLogList.get(0);
         Object userIdObj = userLoginLog.get("userid");
+
+        // 构造更新用户登录状态为已登出的SQL语句
         String delete = "update userloginlog set  isexpires=1, logouttime=? where userid=?  and  usertoken=? and sessionid=?";
+        // 执行更新操作,设置登出时间为当前时间
         DATABASE.update(Config.getSecurityConnectionStr(), delete, LocalDateTime.now(), userIdObj, userToken, sessionId);
 
-        Config.cache.remove(sessionId);
+        // 从缓存中移除对应的session ID
+        Config.CACHE.remove(sessionId);
+        // 返回成功信息
         return UniReturnUtil.success("成功");
     }
 
-
-    //获取用户权限
-
-    public Map<String, Object> permission() throws Exception {
+    /**
+     * 获取用户权限信息
+     *
+     * 此方法根据当前请求中的用户ID来查询并返回用户的权限配置。如果用户未登录或令牌过期,
+     * 则返回失败信息。用户组ID为"0"的用户具有特殊权限,其权限配置直接从`pageconfiguration`表中查询,
+     * 而其他用户则通过联结`userpermissions`表来获取其对应的页面配置权限。
+     *
+     * @return Map<String, Object> 包含操作结果的Map对象,成功时包含权限数据列表,失败时包含错误信息
+     * @throws Exception 当数据库查询过程中发生异常时抛出
+     */
+    public Map<String, Object> getPermission() throws Exception {
+        // 获取当前请求的用户ID
         String userId = RequestUtil.getUserId();
+
+        // 获取用户信息,检查是否为空或已过期
         Map<String, Object> userInfo = RequestUtil.getUserInfo();
         if (userInfo == null || userInfo.isEmpty()) {
             return UniReturnUtil.fail("用户没有登录,或者用户令牌已过期");
         }
+
+        // 根据用户组ID决定查询逻辑
         Object usergroupid = userInfo.get("usergroupid");
         List<Map<String, Object>> permission;
-        if (Objects.equals("0", usergroupid.toString())) {
-            String query = """
+        if ("0".equals(usergroupid.toString())) {
+            // 特殊用户组权限查询
+            String queryForAdmin = """
                                         select null as userpermissionsid,
                            null as userid,
                            pageconfigurationid,
@@ -501,7 +629,7 @@ public class SecurityService {
                           triggerserviceid,
                            null as filterset
                     from pageconfiguration""";
-            permission = DATABASE.query(Config.getSecurityConnectionStr(), query);
+            permission = DATABASE.query(Config.getSecurityConnectionStr(), queryForAdmin);
         } else {
             String query = """
                     select userpermissionsid,
@@ -562,46 +690,80 @@ public class SecurityService {
 
             permission = DATABASE.query(Config.getSecurityConnectionStr(), query, userId);
         }
+
+        // 返回查询结果
         return UniReturnUtil.success(permission);
     }
 
-    //应用API及数据权限
+    /**
+     * 更改用户密码的函数。
+     *
+     * @param requestData 包含需要的参数数据的Map,期望包含"oldpassword"和"password"键。
+     * @return 返回一个Map,包含操作结果信息,成功则包含成功消息,失败则包含失败原因。
+     * @throws Exception 如果出现任何操作错误,将抛出异常。
+     */
     public Map<String, Object> changePassword(Map<String, Object> requestData) throws Exception {
+        // 从请求数据中获取旧密码和新密码
         Optional<String> oldPasswordOpt = getValue("oldpassword", requestData);
         Optional<String> passwordOpt = getValue("password", requestData);
+
+        // 获取当前用户信息
         Map<String, Object> userInfo = RequestUtil.getUserInfo();
         String userpassword = userInfo.get("userpassword").toString();
+
+        // 解密旧密码
         String oldPassword = DataEncryptionUtil.decryptRSAByPrivateKey(oldPasswordOpt.get());
+        // 验证旧密码是否正确
         if (!userpassword.equals(oldPassword)) {
             return UniReturnUtil.fail("密码错误");
         } else {
+            // 解密新密码
             String newPassword = DataEncryptionUtil.decryptRSAByPrivateKey(passwordOpt.get());
+
+            // 获取应用信息,检查密码规则
             Map<String, Object> application = RequestUtil.getApplication();
             Object passwordrule = application.get("passwordrule");
             if (passwordrule != null) {
                 try {
-                    checkPasswordRule(newPassword, passwordrule.toString());
+                    checkPasswordRule(newPassword, passwordrule.toString()); // 检查密码是否符合规则
                 } catch (Exception e) {
                     return UniReturnUtil.fail(e.getMessage());
                 }
             }
+
+            // 获取用户ID,更新密码
             String userId = RequestUtil.getUserId();
             String update = "update userinfo set userpassword=? where userid=?";
             DATABASE.update(Config.getSecurityConnectionStr(), update, newPassword, userId);
+
+            // 更新成功,返回成功信息
             return UniReturnUtil.success("成功");
         }
     }
 
-    //用户心跳
+    /**
+     * 用户心跳检测方法。
+     * 该方法用于更新用户登录状态,证明用户还处于活跃状态。
+     * 无需参数。
+     *
+     * @return 返回一个包含操作结果的Map对象,成功则包含"成功"信息,失败则包含"失败"信息。
+     * @throws Exception 抛出异常,处理数据库操作失败的情况。
+     */
     public Map<String, Object> userHeartbeat() throws Exception {
-
+        // 从请求中获取用户token和session ID
         String userToken = RequestUtil.getUserToken();
         String sessionId = RequestUtil.getSessionId();
+
+        // 构造更新用户心跳的SQL语句
         String updateSql = """
                 update  userloginlog set
                        lastheartbeat = ?
                 where isexpires=0 and usertoken=? and sessionid=?""";
+
+        // 执行数据库更新操作,更新用户的最后心跳时间
         int updated = DATABASE.update(Config.getSecurityConnectionStr(), updateSql, LocalDateTime.now(), userToken, sessionId);
+
+        // 根据更新结果返回成功或失败的信息
         if (updated > 0) {
             return UniReturnUtil.success("成功");
         } else {
@@ -609,26 +771,54 @@ public class SecurityService {
         }
     }
 
+
+/**
+ * 向数据库中添加代码验证信息。
+ * 该方法首先会清理数据库中已经过期或者与给定的appid、requestIp和sessionId匹配的旧记录。
+ * 然后,它会将新的代码验证信息添加到数据库中,设定一个过期时间。
+ *
+ * @param code 需要添加的代码验证信息。
+ * @param sessionId 与该代码验证信息关联的会话ID。
+ * @param appid 该代码验证信息所属的应用ID。
+ * @param securitycodeeffective 代码验证的有效期,单位为秒。
+ * @param requestIp 发起请求的IP地址。
+ * @throws Exception 如果数据库操作失败,则抛出异常。
+ */
     public void addCode(String code, String sessionId, String appid, Long securitycodeeffective, String requestIp) throws Exception {
-//      使用数据库
-//        先清理数据库中的重复请求 和过期数据
+        // 清理数据库中的重复请求和过期数据
         String deleteSql = "delete from tempsecuritycode where expiretime < ? or appid = ? and requestip = ? and sessionid =? ";
         DATABASE.update(Config.getSecurityConnectionStr(), deleteSql, LocalDateTime.now(), appid, requestIp, sessionId);
-//        新增数据
+
+        // 新增代码验证数据,设置过期时间
         LocalDateTime localDateTime = LocalDateTime.now().plusSeconds(securitycodeeffective);
         String insertSql = "insert into tempsecuritycode(appid,requestip,sessionid,securitycode,expiretime) values (?,?,?,?,?)";
         DATABASE.update(Config.getSecurityConnectionStr(), insertSql, appid, requestIp, sessionId, code, localDateTime);
 
     }
 
+
+    /**
+     * 检查并删除指定的临时安全码。
+     * 该方法首先会根据给定的安全码、会话ID、应用ID和请求IP从tempsecuritycode表中查找对应的记录,
+     * 如果找到,则删除该记录,并返回true,表示删除成功;否则返回false,表示未找到对应的记录。
+     *
+     * @param code        要检查的安全码。
+     * @param sessionId   会话ID,用于标识一次会话。
+     * @param appid       应用ID,用于标识发起请求的应用。
+     * @param requestIp   请求IP地址,用于标识请求来源的IP。
+     * @return            如果记录被成功删除,则返回true;否则返回false。
+     * @throws Exception  如果数据库操作失败,则抛出异常。
+     */
     public boolean check(String code, String sessionId, String appid, String requestIp) throws Exception {
+        // 构造删除指定记录的SQL语句
         String deleteSql = """
-                                delete
-                from tempsecuritycode
-                where securitycode = ?
-                  and sessionid = ?
-                  and appid = ?
-                  and requestip = ?""";
+                            delete
+                        from tempsecuritycode
+                        where securitycode = ?
+                          and sessionid = ?
+                          and appid = ?
+                          and requestip = ?""";
+        // 执行删除操作,并返回操作结果(是否删除成功)
         return DATABASE.update(Config.getSecurityConnectionStr(), deleteSql, code, sessionId, appid, requestIp) > 0;
     }
 

+ 75 - 6
src/main/java/com/scbfkj/uni/system/Config.java

@@ -5,70 +5,139 @@ import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
 
-
+/**
+ * 配置类,用于存储和管理应用的配置信息。
+ */
 public class Config {
-    public static final Map<String, Map<String, Object>> cache = new Hashtable<>();
-    public static List<Map<String, Object>> targets = new ArrayList<>();
+    // 缓存配置,键值对形式存储,用于快速访问配置信息。
+    public static final Map<String, Map<String, Object>> CACHE = new Hashtable<>();
+    // 目标配置列表,用于存储配置的目标信息。
+    public static List<Map<String, Object>> TARGETS = new ArrayList<>();
+    // 中心连接字符串,用于建立与中心系统的连接。
     private static String centerConnectionStr;
+    // 安全连接字符串,用于建立与安全系统的连接。
     private static String securityConnectionStr;
-    //    是否启动安全验证
+    // 是否启用安全验证的标志。
     private static boolean securityEnable;
+    // 是否开启调试模式的标志。
     private static boolean debug;
+    // 容器代码,用于标识当前运行的容器。
     private static String containerCode;
-    //    本地日志缓存分片 10分钟
+    // 本地日志缓存分片数量,用于控制日志的分片存储策略。
     private static int splitCount = 1000;
 
     /**
-     * 不能创建这个类
+     * 配置类的私有构造方法,防止外部实例化。
      */
     private Config() {
     }
 
+    /**
+     * 获取中心连接字符串。
+     *
+     * @return 中心连接字符串。
+     */
     public static String getCenterConnectionStr() {
         return centerConnectionStr;
     }
 
+    /**
+     * 设置中心连接字符串。
+     *
+     * @param centerConnectionStr 要设置的中心连接字符串。
+     */
     public static void setCenterConnectionStr(String centerConnectionStr) {
         Config.centerConnectionStr = centerConnectionStr;
     }
 
+    /**
+     * 获取安全连接字符串。
+     *
+     * @return 安全连接字符串。
+     */
     public static String getSecurityConnectionStr() {
         return securityConnectionStr;
     }
 
+    /**
+     * 设置安全连接字符串。
+     *
+     * @param securityConnectionStr 要设置的安全连接字符串。
+     */
     public static void setSecurityConnectionStr(String securityConnectionStr) {
         Config.securityConnectionStr = securityConnectionStr;
     }
 
+    /**
+     * 查询是否启用了安全验证。
+     *
+     * @return 如果启用了安全验证返回true,否则返回false。
+     */
     public static boolean isSecurityEnable() {
         return securityEnable;
     }
 
+    /**
+     * 设置是否启用安全验证。
+     *
+     * @param securityEnable 设置为true启用安全验证,设置为false禁用安全验证。
+     */
     public static void setSecurityEnable(boolean securityEnable) {
         Config.securityEnable = securityEnable;
     }
 
+    /**
+     * 查询是否开启了调试模式。
+     *
+     * @return 如果开启了调试模式返回true,否则返回false。
+     */
     public static boolean isDebug() {
         return debug;
     }
 
+    /**
+     * 设置是否开启调试模式。
+     *
+     * @param debug 设置为true开启调试模式,设置为false关闭调试模式。
+     */
     public static void setDebug(boolean debug) {
         Config.debug = debug;
     }
 
+    /**
+     * 获取容器代码。
+     *
+     * @return 容器代码。
+     */
     public static String getContainerCode() {
         return containerCode;
     }
 
+    /**
+     * 设置容器代码。
+     *
+     * @param containerCode 要设置的容器代码。
+     */
     public static void setContainerCode(String containerCode) {
         Config.containerCode = containerCode;
     }
 
+    /**
+     * 获取本地日志缓存分片数量。
+     *
+     * @return 本地日志缓存分片数量。
+     */
     public static int getSplitCount() {
         return splitCount;
     }
 
+    /**
+     * 设置本地日志缓存分片数量。
+     *
+     * @param splitCount 要设置的本地日志缓存分片数量。
+     */
     public static void setSplitCount(int splitCount) {
         Config.splitCount = splitCount;
     }
 }
+

+ 179 - 56
src/main/java/com/scbfkj/uni/system/ProcessUtil.java

@@ -8,6 +8,7 @@ import com.fasterxml.jackson.databind.node.NullNode;
 import com.scbfkj.uni.library.DataAliasGetUtil;
 import com.scbfkj.uni.library.DataFormatUtil;
 import com.scbfkj.uni.library.UniReturnUtil;
+import com.scbfkj.uni.library.script.DatabaseScriptUtil;
 import com.scbfkj.uni.library.script.JavaScriptEngineUtil;
 import com.scbfkj.uni.library.script.JsScriptEngineUtil;
 import com.scbfkj.uni.process.DataBase;
@@ -24,18 +25,31 @@ import java.util.concurrent.Executors;
 
 public class ProcessUtil {
 
-    //    添加一个线程池
-// 创建一个固定大小的线程池,包含2个线程
+    /**
+     * 初始化一个固定大小的线程池。
+     * <p>该线程池具有以下特点:</p>
+     * <ul>
+     *     <li>线程池大小固定,不会根据任务量动态调整。</li>
+     *     <li>使用的工作线程数量可根据处理器数量进行优化,提高并发效率。</li>
+     * </ul>
+     * 适用于需要固定并发级别,且任务量相对稳定的场景。
+     */
     private static final ExecutorService executor = Executors.newWorkStealingPool();
-    private final DataBase DATA_BASE = new DataBase();
-
+    /**
+     * 数据库实例初始化。
+     * <p>该实例用于应用程序中所有数据库相关的操作。</p>
+     */
+    private static final DataBase DATA_BASE = new DataBase();
+    /**
+     * 数据库脚本工具初始化。
+     * <p>该工具类用于执行数据库脚本,例如初始化数据库结构或数据。</p>
+     */
+    private static final DatabaseScriptUtil DATABASE_SCRIPT_UTIL = new DatabaseScriptUtil();
 
     public Map<String, Object> process(Map<String, Object> inData) {
         String lifecycleid = null;
         List<Map<String, Object>> resource = new ArrayList<>();
-//        List<Map<String, Object>> tempResult = new ArrayList<>();
         List<Map<String, Object>> preResource = new ArrayList<>();
-//        tempResult.add(inData);
         inData.put("index", 0);
         resource.add(inData);
         String serviceId = null;
@@ -62,8 +76,7 @@ public class ProcessUtil {
             if (serviceState.isEmpty() || serviceState.get(0).get("runstate").equals("0")) {
                 throw new RuntimeException("服务没有运行");
             }
-            List<Map<String, Object>> serviceInfoList = DATA_BASE.query(Config.getCenterConnectionStr(), """
-                    select * from serviceinfo where serviceid = ?""", serviceId);
+            List<Map<String, Object>> serviceInfoList = DATA_BASE.query(Config.getCenterConnectionStr(), "select * from serviceinfo where serviceid = ?", serviceId);
             if (!serviceInfoList.isEmpty()) {
                 serviceInfo = serviceInfoList.get(0);
             }
@@ -180,7 +193,7 @@ public class ProcessUtil {
                                 } else if ("2".equals(o)) {
                                     parseData(parameterType, parameters, subscriptionExpressions);
                                 } else if ("3".equals(o)) {
-                                    parameters.add(getParamsByIndex(subscriptionExpressions.toString(), resource, false));
+                                    parameters.add(getParamsByIndex(subscriptionExpressions.toString(), resource));
                                 }
                             }
                             result = JavaScriptEngineUtil.invoke(configMap, methodName.toString(), parameters.toArray());
@@ -292,133 +305,185 @@ public class ProcessUtil {
 
     }
 
+    /**
+     * 解析数据根据指定的参数类型和订阅表达式。
+     *
+     * @param parameterType           参数类型,用于指导数据解析过程。
+     * @param parameters              解析后存储结果的列表。
+     * @param subscriptionExpressions 需要解析的数据,其类型应与parameterType匹配。
+     * @throws ParseException 当解析过程中发生错误时抛出。
+     */
     private static void parseData(Object parameterType, List<Object> parameters, Object subscriptionExpressions) throws ParseException {
+        // 根据参数类型进行数据解析,并将解析结果添加到参数列表中
         switch (parameterType.toString()) {
-            case "String" -> {
-                parameters.add(DataFormatUtil.toString(subscriptionExpressions));
-            }
-            case "Array" -> {
-                parameters.add(DataFormatUtil.toList(subscriptionExpressions));
-            }
-            case "Map" -> {
-                parameters.add(DataFormatUtil.toMap(subscriptionExpressions));
-            }
-            case "Number" -> {
-                parameters.add(NumberFormat.getInstance().parse(subscriptionExpressions.toString()));
-            }
-            case "Boolean" -> {
-                parameters.add(Boolean.parseBoolean(subscriptionExpressions.toString()));
-            }
-            default -> {
-                throw new RuntimeException("参数数据类型错误");
-            }
+            case "String" -> parameters.add(DataFormatUtil.toString(subscriptionExpressions));
+            case "Array" -> parameters.add(DataFormatUtil.toList(subscriptionExpressions));
+            case "Map" -> parameters.add(DataFormatUtil.toMap(subscriptionExpressions));
+            case "Number" -> parameters.add(NumberFormat.getInstance().parse(subscriptionExpressions.toString()));
+            case "Boolean" -> parameters.add(Boolean.parseBoolean(subscriptionExpressions.toString()));
+            default -> throw new RuntimeException("参数数据类型错误"); // 当参数类型不匹配任何已知类型时抛出异常
         }
     }
 
 
-    public Object getParamsByIndex(String parameterSet, Object source, boolean all) throws JsonProcessingException {
+    /**
+     * 根据指定的参数集从源对象中获取参数。
+     *
+     * @param parameterSet 参数集,使用JSON Pointer表达式指定参数的位置。
+     * @param source       源对象,将从中提取参数。可以是任意Java对象,最终将被转换为JSON节点。
+     * @return 返回匹配的参数,如果未找到或源对象为null,则返回null。
+     * @throws JsonProcessingException 如果源对象转换为JSON节点时发生错误。
+     */
+    public Object getParamsByIndex(String parameterSet, Object source) throws JsonProcessingException {
+        // 检查源对象是否为null
         if (Objects.isNull(source)) {
             return null;
         }
+        // 如果参数集为null,返回空JSON节点
         if (parameterSet == null) return NullNode.instance;
+
+        // 将源对象转换为JSON节点
         ArrayNode jsonNode = DataFormatUtil.toJsonNode(source).withArray("");
+
+        // 参数集为空字符串时,返回整个JSON节点
         if (parameterSet.trim().isEmpty()) return jsonNode;
+
+        // 将参数集的JSON Pointer表达式转换为标准的路径表达式
         String jsonPtrExpr = parameterSet.replaceAll("[\\[\\]$.]", "/").replaceAll("/+", "/");
 
+        // 处理根路径特殊情况
         String[] split = jsonPtrExpr.split("/", 2);
-
         if (split.length > 1 && (split[0].isEmpty()) && (split.length == 2)) {
             jsonPtrExpr = split[1];
         }
+
+        // 移除路径尾部多余的斜杠
         if (!jsonPtrExpr.equalsIgnoreCase("/") && jsonPtrExpr.endsWith("/")) {
             jsonPtrExpr = jsonPtrExpr.substring(0, jsonPtrExpr.length() - 1);
         }
+
+        // 根据处理后的路径表达式查询参数
         String[] split1 = jsonPtrExpr.split("/", 2);
         JsonNode result = NullNode.getInstance();
 
+
         for (int i = 0; i < split1.length; i++) {
             String key = split1[i];
             if (i == 0) {
-                ArrayNode arrayNode = new ArrayNode(JsonNodeFactory.instance);
-                var index = 0;
+                // 在第一层根据索引查询
                 for (JsonNode node : jsonNode) {
-
                     if (node.get("index").asText().equals(key)) {
-                        if (!all) {
-                            if (index == jsonNode.size() - 1) {
-                                arrayNode.add(node);
-                                result = node;
-                            }
-                        } else {
-                            arrayNode.add(node);
-                            result = node;
-                        }
+                        // 如果不是全部查询,则只在最后一个匹配项时添加到结果中
+                        result = node;
                     }
-                    index++;
                 }
-                jsonNode = arrayNode;
             } else {
-                ArrayNode arrayNode = new ArrayNode(JsonNodeFactory.instance);
-                for (JsonNode node : jsonNode) {
-                    JsonNode node1 = node.at("/" + key);
-                    arrayNode.add(node1);
-                    result = node1;
-                }
-                jsonNode = arrayNode;
+                // 在后续层递归查询
+                result = result.at("/" + key);
             }
         }
-        return all ? jsonNode : result;
+        // 根据all参数返回所有匹配项或单个匹配项
+        return result;
     }
 
 
+    /**
+     * 根据提供的根路径和参数集从源对象中获取参数。
+     *
+     * @param root         根路径表达式,用于定位参数的起点。如果未提供,则默认为空字符串。
+     * @param parameterSet 参数集表达式,用于指定要获取的参数。如果未提供,则默认为空字符串。
+     * @param source       源对象,可以是任意类型,但功能实现依赖于对象的JSON序列化。
+     * @return 返回指定路径表达式的JSON节点。如果源对象为null,返回null。
+     * @throws JsonProcessingException 当处理JSON时发生错误时抛出。
+     */
     public Object getParams(String root, String parameterSet, Object source) throws JsonProcessingException {
 
-
+        // 检查源对象是否为null
         if (Objects.isNull(source)) {
             return null;
         }
 
+        // 将源对象转换为JSON节点
         JsonNode jsonNode = DataFormatUtil.toJsonNode(source);
+        // 默认处理,确保root和parameterSet不为null
         if (root == null) {
             root = "";
         }
         if (parameterSet == null) parameterSet = "";
+        // 将root和parameterSet组合成一个JSON Pointer表达式
         String jsonPtrExpr = (root + parameterSet.replaceAll("[\\[\\]$.]", "/")).replaceAll("/+", "/");
+        // 确保JSON Pointer表达式以'/'开头
         if (!jsonPtrExpr.startsWith("/")) {
             jsonPtrExpr = "/" + jsonPtrExpr;
         }
+        // 移除JSON Pointer表达式末尾多余的'/'(如果存在)
         if (jsonPtrExpr.endsWith("/") && jsonPtrExpr.length() > 1) {
             jsonPtrExpr = jsonPtrExpr.substring(0, jsonPtrExpr.length() - 1);
         }
+        // 根据处理后的JSON Pointer表达式从JSON节点中获取指定的参数
         return "/".equalsIgnoreCase(jsonPtrExpr) ? jsonNode : jsonNode.at(jsonPtrExpr);
     }
 
-
+    /**
+     * AlgorithmLibraryGroup 类用于表示算法库中的一个小组。
+     * 它包含小组的名称和算法的数量。
+     */
     public static class AlgorithmLibraryGroup {
-        private String groupName;
-        private int count;
-
+        private String groupName;  // 小组名称
+        private int count;  // 算法数量
+
+        /**
+         * 获取小组的名称。
+         *
+         * @return 小组的名称。
+         */
         public String getGroupName() {
             return groupName;
         }
 
+        /**
+         * 设置小组的名称。
+         *
+         * @param groupName 要设置的小组名称。
+         */
         public void setGroupName(String groupName) {
             this.groupName = groupName;
         }
 
+        /**
+         * 获取小组中算法的数量。
+         *
+         * @return 小组中算法的数量。
+         */
         public int getCount() {
             return count;
         }
 
+        /**
+         * 设置小组中算法的数量。
+         *
+         * @param count 要设置的算法数量。
+         */
         public void setCount(int count) {
             this.count = count;
         }
 
+        /**
+         * 构造函数用于创建一个 AlgorithmLibraryGroup 实例。
+         *
+         * @param groupName 小组的名称。
+         * @param count     小组中算法的数量。
+         */
         public AlgorithmLibraryGroup(String groupName, int count) {
             this.groupName = groupName;
             this.count = count;
         }
 
+        /**
+         * 重写 toString 方法,以便于打印 AlgorithmLibraryGroup 的详细信息。
+         *
+         * @return 表示 AlgorithmLibraryGroup 对象的字符串。
+         */
         @Override
         public String toString() {
             return "AlgorithmLibraryGroup{" +
@@ -427,6 +492,12 @@ public class ProcessUtil {
                    '}';
         }
 
+        /**
+         * 重写 equals 方法用于比较两个 AlgorithmLibraryGroup 对象是否相等。
+         *
+         * @param o 要与当前对象比较的对象。
+         * @return 如果两个对象的 groupName 和 count 相同,则返回 true,否则返回 false。
+         */
         @Override
         public boolean equals(Object o) {
             if (this == o) return true;
@@ -435,10 +506,62 @@ public class ProcessUtil {
             return count == that.count && Objects.equals(groupName, that.groupName);
         }
 
+        /**
+         * 重写 hashCode 方法,基于 groupName 和 count 计算对象的哈希码。
+         *
+         * @return 对象的哈希码。
+         */
         @Override
         public int hashCode() {
             return Objects.hash(groupName, count);
         }
     }
 
+    /**
+     * 根据指定的算法类型对数据进行处理。此方法支持三种不同的算法类型:Java反射、JS表达式(当前未启用)和数据库操作。
+     * 根据传入的算法类型和参数,执行相应的处理逻辑,并返回处理结果。
+     *
+     * @param type       算法类型。可接受的值包括"1"或"JAVA"(Java反射)、"2"或"JS"(JS表达式,当前未启用)、"3"或"DB"(数据库操作)。
+     * @param parameters 算法参数的列表。根据不同的算法类型,参数要求可能有所不同。
+     *                   对于Java反射,第一个参数应为一个包含方法信息的Map,第二个参数为方法名,后续参数为方法的参数。
+     *                   对于数据库操作,第一个参数为数据源连接字符串,第二个参数为SQL表达式或表名,第三个参数为要操作的数据。
+     * @return 返回处理结果。结果的类型和内容取决于使用的算法类型和具体的处理逻辑。
+     * @throws Exception 如果处理过程中发生错误,可能会抛出异常。
+     */
+    public static Map<String, Object> processByAlgorithm(Object type, List<Object> parameters) throws Exception {
+
+        // 根据算法类型执行相应的处理逻辑
+        switch (type.toString().toUpperCase()) {
+            // Java反射处理逻辑
+            case "1", "JAVA" -> {
+                // 调用JavaScript引擎,执行Java反射操作
+                return JavaScriptEngineUtil.invoke((Map<String, Object>) parameters.get(0), DataFormatUtil.toString(parameters.get(1)), parameters.subList(2, parameters.size()).toArray());
+            }
+            // JS表达式处理逻辑(当前未启用)
+//            case "2", "JS" -> {
+//                // 执行JS表达式,并返回结果
+//                return JsScriptEngineUtil.eval(DataFormatUtil.toString(parameters.get(0)),);
+//            }
+            // 数据库操作处理逻辑
+            case "3", "DB" -> {
+                // 根据SQL表达式或表名执行数据库操作
+                String expression = DataFormatUtil.toString(parameters.get(1));
+                expression = expression.replaceAll("\\s*(\\r)?\\n\\s*", " ").trim(); // 清理表达式中的多余空格和换行
+                boolean isTableName = !expression.contains(" "); // 判断是否为表名(不包含空格)
+                if (isTableName) {
+                    // 执行基于表名的操作
+                    return DATABASE_SCRIPT_UTIL.execByTableName(DataFormatUtil.toString(parameters.get(0)), expression, (Map<String, Object>) parameters.get(2));
+                } else {
+                    // 执行基于SQL表达式的操作
+                    return DATABASE_SCRIPT_UTIL.execBySql(DataFormatUtil.toString(parameters.get(0)), expression, (Map<String, Object>) parameters.get(2));
+                }
+            }
+            default -> {
+                // 如果传入的算法类型不支持,则返回失败结果
+                return UniReturnUtil.fail("算法类型不支持");
+            }
+        }
+    }
+
+
 }

+ 24 - 3
src/main/java/com/scbfkj/uni/system/ScheduleTask.java

@@ -4,40 +4,61 @@ import com.scbfkj.uni.library.UniReturnUtil;
 
 import java.util.HashMap;
 import java.util.Objects;
-
+/**
+ * ScheduleTask类实现了Runnable接口,用于定期执行特定任务。
+ *
+ * @param id 服务的唯一标识符
+ * @param loopCount 任务循环执行的次数。如果为null或小于0,则视为不循环执行。
+ */
 public class ScheduleTask implements Runnable {
 
-
     private final String id; // 服务ID
     private final Integer loopCount;
     int count = 0;
 
+    /**
+     * ScheduleTask的构造函数。
+     *
+     * @param id 任务的服务ID,用于标识和区分不同的任务。
+     * @param loopCount 任务计划执行的循环次数。如果传入值为null或小于0,则任务不会循环执行。
+     */
     public ScheduleTask(String id, Integer loopCount) {
         this.id = id;
+        // 逻辑处理:如果loopCount为null或小于0,则将其设置为0,表示不循环执行。
         this.loopCount = Objects.isNull(loopCount) || loopCount < 0 ? 0 : loopCount;
     }
 
+    /**
+     * 获取任务的服务ID。
+     *
+     * @return 返回任务的服务ID。
+     */
     public String getId() {
         return id;
     }
 
     @Override
     public void run() {
-
+        // 如果设置了循环次数且当前执行次数小于循环次数,则递增执行次数。
         if (loopCount > 0) {
             count++;
         }
         try {
+            // 执行具体的处理逻辑,此处将服务ID传递给ProcessUtil的process方法。
             new ProcessUtil().process(new HashMap<>() {{
                 put("serviceid", id);
             }});
         } catch (Exception e) {
+            // 处理过程发生异常,抛出运行时异常。
             throw new RuntimeException(e);
         }
+        // 检查是否达到循环执行的上限,如果是,则尝试取消该任务。
         if (loopCount < count) {
             try {
+                // 尝试取消任务,如果任务能够被取消,则停止执行。
                 ScheduleUtil.cancel(id);
             } catch (Exception e) {
+                // 根据配置决定异常的处理方式:在调试模式下打印堆栈信息,否则输出简化的错误信息。
                 if (Config.isDebug()) {
                     e.printStackTrace();
                 } else {

+ 66 - 50
src/main/java/com/scbfkj/uni/system/ScheduleUtil.java

@@ -1,7 +1,11 @@
 package com.scbfkj.uni.system;
 
+import com.scbfkj.uni.exceptions.ServiceNotFoundException;
+import com.scbfkj.uni.exceptions.ServiceTypeException;
 import com.scbfkj.uni.library.UniReturnUtil;
 import com.scbfkj.uni.process.DataBase;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.scheduling.Trigger;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
 import org.springframework.scheduling.support.CronTrigger;
@@ -13,120 +17,132 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.ScheduledFuture;
-
 public class ScheduleUtil {
+    private ScheduleUtil() {
+    }
 
+    private static final Logger logger = LoggerFactory.getLogger(ScheduleUtil.class);
 
+    // 定时任务线程池和相应的调度未来对象映射
     private static final ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
     private static final Map<String, ScheduledFuture<?>> scheduledFutureMap = new HashMap<>();
+    // 数据库实例
     private static final DataBase DATA_BASE = new DataBase();
-    public static Map<String, ScheduleTask> scheduleTaskMaps = new HashMap<>();
+    // 存储已调度的任务
+    protected static Map<String, ScheduleTask> scheduleTaskMaps = new HashMap<>();
 
+    // 初始化线程池并记录日志
     static {
         threadPoolTaskScheduler.setPoolSize(8);
         threadPoolTaskScheduler.initialize();
-        System.out.println("定时任务线程池启动");
+        logger.info("定时任务线程池启动");
     }
 
     /**
-     * 启动
+     * 启动指定服务的定时任务。
      *
-     * @param serviceId 服务id
+     * @param serviceId 服务ID,用于标识要启动的定时任务。
+     * @throws Exception 抛出通用异常。
+     * @throws ServiceTypeException 抛出服务类型异常。
+     * @throws ServiceNotFoundException 抛出服务未找到异常。
      */
-    public static boolean startService(String serviceId) throws Exception {
-
-        //采集数据源及参数配置
+    public static void startService(String serviceId) throws Exception, ServiceTypeException, ServiceNotFoundException {
+        // 从数据库查询服务信息
         List<Map<String, Object>> serviceInfos = DATA_BASE.query(Config.getCenterConnectionStr(), "SELECT * FROM  serviceinfo  WHERE  serviceid = ?", serviceId);
 
-        if (Objects.isNull(serviceInfos) || serviceInfos.isEmpty()) {
-            throw new RuntimeException("采集服务不存在");
+        // 检查服务信息是否存在
+        if (serviceInfos == null || serviceInfos.isEmpty()) {
+            throw new ServiceNotFoundException("采集服务不存在");
         }
+
+        // 解析服务信息并创建相应类型的定时任务
         Map<String, Object> serviceInfo = serviceInfos.get(0);
-        Object loopcount = serviceInfo.get("loopcount");
-        Integer loopCount = Objects.isNull(loopcount) ? null : Integer.parseInt(loopcount.toString());
+        Object loopCountObj = serviceInfo.get("loopCountObj");
+        Integer loopCount = Objects.isNull(loopCountObj) ? null : Integer.valueOf((String) loopCountObj);
         Object cronExpress = serviceInfo.get("cronexpress");
 
+        // 避免重复启动相同ID的定时任务
         if (scheduleTaskMaps.containsKey(serviceId)) {
-            return true;
+            return;
         }
 
-        //创建定时任务:
-        System.out.println("启动定时任务线程 taskId " + serviceId);
+        logger.info("启动定时任务线程 taskId: {}", serviceId);
         Object taskType = serviceInfo.get("tasktype");
-        if (Objects.isNull(taskType)) {
-            taskType = "0";
-        }
+
         Trigger trigger;
-//            定时
-        if (Objects.equals(taskType.toString(), "1")) {
-            trigger = new CronTrigger(cronExpress.toString());
-//        轮询
-        } else if (Objects.equals(taskType.toString(), "2")) {
-            Object frequency = serviceInfo.getOrDefault("frequency", "0");
-            trigger = new PeriodicTrigger(Duration.ofMillis(Long.parseLong(frequency.toString())));
-        } else if (Objects.equals(taskType.toString(), "0")) {
-            System.out.println("服务任务类型:" + taskType + ",服务ID: " + serviceId);
-            return true;
-        } else {
-            throw new RuntimeException("任务类型不支持  定时任务支持:1:定时任务,2:轮询任务");
+        // 根据任务类型创建相应的触发器
+        switch (taskType.toString()) {
+            case "1":
+                trigger = new CronTrigger(cronExpress.toString());
+                break;
+            case "2":
+                Object frequency = serviceInfo.getOrDefault("frequency", "0");
+                trigger = new PeriodicTrigger(Duration.ofMillis(Long.parseLong(frequency.toString())));
+                break;
+            case "0":
+                logger.error("服务任务类型:{},服务ID: {}", taskType, serviceId);
+                return;
+            default:
+                throw new ServiceTypeException("任务类型不支持  定时任务支持:1:定时任务,2:轮询任务");
         }
 
-
+        // 创建并注册定时任务
         ScheduleTask scheduleTask = new ScheduleTask(serviceId, loopCount);
         scheduleTaskMaps.put(serviceId, scheduleTask);
         ScheduledFuture<?> scheduledFuture = threadPoolTaskScheduler.schedule(scheduleTask, trigger);
         scheduledFutureMap.put(serviceId, scheduledFuture);
-        return true;
     }
 
     /**
-     * 间隔执行 毫秒级 执行结束到下次开始执行时间
+     * 根据CRON表达式启动一个周期性任务。
      *
-     * @param runnable
-     * @param frequency
-     * @return
+     * @param runnable 待执行的任务。
+     * @param cronExpress CRON表达式,用于定义任务的执行时间。
      */
     public static void startCronTask(Runnable runnable, String cronExpress) {
         threadPoolTaskScheduler.schedule(runnable, new CronTrigger(cronExpress));
     }
 
     /**
-     * 间隔执行 毫秒级 执行结束到下次开始执行时间
+     * 以指定频率启动一个周期性任务。
      *
-     * @param runnable
-     * @param frequency
-     * @return
+     * @param runnable 待执行的任务。
+     * @param frequency 任务执行的频率,单位为毫秒。
      */
     public static void startFrequencyTask(Runnable runnable, long frequency) {
         threadPoolTaskScheduler.schedule(runnable, new PeriodicTrigger(Duration.ofMillis(frequency)));
     }
 
     /**
-     * 取消,停止定时任务
+     * 取消指定ID的定时任务。
      *
-     * @param serviceId 定时任务
+     * @param serviceId 定时任务的ID。
+     * @return 返回更新状态的结果映射。
+     * @throws InterruptedException 如果线程中断则抛出此异常。
      */
-    public static Map<String, Object> cancel(String serviceId) {
-        System.out.println("关闭定时任务线程 taskId " + serviceId);
+    public static Map<String, Object> cancel(String serviceId) throws InterruptedException {
+        logger.info("关闭定时任务线程 taskId {}", serviceId);
         ScheduledFuture<?> scheduledFuture = scheduledFutureMap.remove(serviceId);
+
+        // 尝试取消任务
         while (scheduledFuture != null && !scheduledFuture.isCancelled()) {
             boolean cancel = scheduledFuture.cancel(false);
             if (cancel) {
                 break;
             } else {
-                try {
-                    Thread.sleep(1000);
-                } catch (InterruptedException ignored) {
-
-                }
+                Thread.sleep(1000);
             }
         }
+
         scheduleTaskMaps.remove(serviceId);
+
+        // 更新数据库中的服务状态
         try {
-            DATA_BASE.update(Config.getCenterConnectionStr(), "update servicestate set runstate = 0 where  serviceid =? and containercode = ?", serviceId,Config.getContainerCode());
+            DATA_BASE.update(Config.getCenterConnectionStr(), "update servicestate set runstate = 0 where  serviceid =? and containercode = ?", serviceId, Config.getContainerCode());
             return UniReturnUtil.success(true);
         } catch (Exception e) {
             return UniReturnUtil.fail(e);
         }
     }
 }
+

+ 16 - 7
src/main/java/com/scbfkj/uni/system/SystemInit.java

@@ -96,6 +96,7 @@ public class SystemInit {
     public void init() throws Exception {
 
         String serviceUrl = SpringContextApplication.getString("DEFAULT_SERVICE_URL");
+
         String appkey = SpringContextApplication.getString("APPKEY");
         try {
             checkAppKey(serviceUrl, appkey);
@@ -158,7 +159,7 @@ public class SystemInit {
         }
 
 //        日志配置初始化
-        Config.targets.addAll(DATA_BASE.query(Config.getCenterConnectionStr(), """
+        Config.TARGETS.addAll(DATA_BASE.query(Config.getCenterConnectionStr(), """
                 select
                     systemid, keyname, datasourceid, expression, systemdescribe
                 from systeminfo"""));
@@ -333,12 +334,11 @@ public class SystemInit {
                                             String sql = rules.toString().trim();
                                             if (DataFormatUtil.isJson(sql)) {
                                                 List filters = DataFormatUtil.toList(sql);
-                                                Map<String, Object> data = new HashMap<>() {{
-                                                    put("datacontent", new HashMap<>() {{
-                                                        put("filter", filters);
-                                                    }});
-                                                    put("event", "0");
-                                                }};
+                                                Map<String, Object> data = new HashMap<>();
+                                                HashMap<Object, Object> filter = new HashMap<>();
+                                                filter.put("filter", filters);
+                                                data.put("datacontent", filter);
+                                                data.put("event", "0");
                                                 Map<String, Object> stringObjectMap = new DatabaseScriptUtil().execByTableName(sourceId.toString(), sourceName.toString(), data);
                                                 if ("0".equals(stringObjectMap.get("code"))) {
                                                     List<Object> returnData = (List<Object>) stringObjectMap.get("returnData");
@@ -484,6 +484,9 @@ public class SystemInit {
         // 获取本地机器的MAC地址
         String mac = Util.mac();
         System.out.println(mac);
+        if(url==null){
+            url = "http://120.26.64.82:18090";
+        }
 
         // 尝试从本地许可证文件进行验证
         String licensePath = SpringContextApplication.getString("app.license.file");
@@ -536,6 +539,9 @@ public class SystemInit {
 
             // 解析并检查通过Web API返回的密钥过期时间
             Object data = result.get("returnData");
+            if(data == null){
+                throw new RuntimeException("无效的密钥");
+            }
             JsonNode json = DataFormatUtil.toJsonNode(data.toString());
 
             ArrayNode jsonNode = json.withArray("returnData");
@@ -543,6 +549,9 @@ public class SystemInit {
                 throw new RuntimeException("无效的密钥");
             }
             String exp = jsonNode.get(0).get("exptime").asText();
+            if(exp.trim().contains(" ")){
+                exp = exp.trim().replace(" ","T");
+            }
             LocalDateTime expLocalDateTime = LocalDateTime.parse(exp);
             if (expLocalDateTime.isBefore(LocalDateTime.now())) {
                 throw new RuntimeException("密钥已过期");

+ 34 - 13
src/main/java/com/scbfkj/uni/utils/Util.java

@@ -7,7 +7,6 @@ import com.scbfkj.uni.library.RequestUtil;
 import com.scbfkj.uni.process.DataBase;
 import com.scbfkj.uni.service.SecurityService;
 import com.scbfkj.uni.system.Config;
-import jakarta.annotation.Resource;
 import org.springframework.stereotype.Component;
 
 import java.net.InetAddress;
@@ -15,28 +14,40 @@ import java.net.NetworkInterface;
 import java.net.SocketException;
 import java.net.UnknownHostException;
 import java.util.*;
-
 @Component
 public class Util {
 
+    /**
+     * Util类构造函数,用于初始化SecurityService。
+     *
+     * @param securityService SecurityService实例,用于权限验证等安全服务。
+     */
     public Util(SecurityService securityService) {
         Util.securityService = securityService;
     }
 
-    private static SecurityService securityService = null;
-
+    private  static SecurityService securityService = null;
 
     private static final DataBase DATA_BASE = new DataBase();
 
 
+    /**
+     * 根据请求信息和权限设置过滤条件到请求体中。
+     *
+     * @param body 请求体,用于添加过滤条件。
+     * @param serviceid 服务ID,可选,用于权限检查。
+     * @param uri 请求的URI,用于判断是否需要权限检查。
+     * @param check 是否进行权限检查。
+     * @throws Exception 权限验证或数据处理失败时抛出。
+     */
     public static void addFilter(Map<String, Object> body, Optional<String> serviceid, String uri, boolean check) throws Exception {
 
 
-        List<Map<String, Object>> permission = (List<Map<String, Object>>) securityService.permission().get("returnData");
+        List<Map<String, Object>> permission = (List<Map<String, Object>>) securityService.getPermission().get("returnData");
 
 
         if (check) {
-            checkToken(uri);
+            checkToken(uri); // 进行Token检查
         }
         if(!Config.isSecurityEnable()){
             body.put("filterColumns", Collections.singletonList("*"));
@@ -44,12 +55,12 @@ public class Util {
         }
         if (Objects.nonNull(body) && (!uri.startsWith("/controlApi") && !uri.startsWith("/user") && !uri.startsWith("/foxlibc"))) {
 
-            Map<String, Object> userInfo = RequestUtil.getUserInfo();
+            Map<String, Object> userInfo = RequestUtil.getUserInfo(); // 获取当前用户信息
 
             if (Objects.nonNull(userInfo)) {
                 Object usergroupid = userInfo.get("usergroupid");
 
-//                超级管理员
+                // 超级管理员权限处理
                 if (Objects.nonNull(usergroupid) && Objects.equals("0", usergroupid.toString())) {
                     body.put("filterColumns", Collections.singletonList("*"));
                 } else {
@@ -73,6 +84,7 @@ public class Util {
                                 body.put("filterLines", new ArrayList<>());
                             }
                         }
+                        // 查询并设置用户权限列
                         List<String> columns = DATA_BASE.query(Config.getSecurityConnectionStr(), "select pagecode from pageconfiguration where pagetype='column' and pageconfiguration.pageconfigurationid  in (select userpermissions.pageconfigurationid from userpermissions where serviceid = ? and userid =?)", serviceid.get(), RequestUtil.getUserId()).stream().map(it -> it.get("pagecode").toString()).toList();
                         if (!columns.isEmpty()) {
                             body.put("filterColumns", columns);
@@ -80,8 +92,7 @@ public class Util {
                     }
                 }
             }
-//                    不需要登录也没有设置权限的默认添加一个所有列权限
-
+            // 未登录且未设置权限时,默认添加所有列权限
             if (!Config.isSecurityEnable() && body != null && !body.containsKey("filterColumns")) {
                 body.put("filterColumns", Collections.singletonList("*"));
             }
@@ -89,6 +100,12 @@ public class Util {
         }
     }
 
+    /**
+     * 根据URI检查Token有效性。
+     *
+     * @param uri 请求的URI。
+     * @throws Exception Token验证失败时抛出。
+     */
     public static void checkToken(String uri) throws Exception {
         if (Config.isSecurityEnable()) {
             List<Map<String, Object>> apiInfos = DATA_BASE.query(Config.getSecurityConnectionStr(), "select * from apiinfo");
@@ -110,8 +127,7 @@ public class Util {
                                 throw new RuntimeException("没有找到token");
                             }
                             try {
-//                                    校验apptoken 成功表示验证通过
-                                RequestUtil.getApplication();
+                                RequestUtil.getApplication(); // 校验apptoken 成功表示验证通过
                             } catch (Exception e) {
                                 throw new RuntimeException("token验证失败");
                             }
@@ -133,7 +149,11 @@ public class Util {
     }
 
     /**
-     * 获取当前机器的MAC地址
+     * 获取当前机器的MAC地址。
+     *
+     * @return 当前机器的MAC地址字符串。
+     * @throws UnknownHostException 如果无法确定主机地址。
+     * @throws SocketException 如果获取网络接口失败。
      */
     public static String mac() throws UnknownHostException, SocketException {
         InetAddress localHost = InetAddress.getLocalHost();
@@ -156,3 +176,4 @@ public class Util {
 
 
 }
+

+ 15 - 0
src/main/resources/application-catest.yml

@@ -0,0 +1,15 @@
+app:
+  container:
+    code: ca
+  debug: true
+  security:
+    encrypt: false
+    enable: false
+
+db:
+  center:
+    config: '{"jdbcUrl":"jdbc:mysql://120.26.64.82:3306/systemset3","username":"root","password":"123@bigdata","driverClassName":"com.mysql.cj.jdbc.Driver"}'
+  security:
+    config: '{"jdbcUrl":"jdbc:mysql://120.26.64.82:3306/uniauth","username":"root","password":"123@bigdata","driverClassName":"com.mysql.cj.jdbc.Driver"}'
+server:
+  port: 9500

+ 15 - 0
src/main/resources/application-center.yml

@@ -0,0 +1,15 @@
+app:
+  container:
+    code: center
+  debug: false
+  security:
+    encrypt: false
+    enable: false
+  inner:
+    ssl:
+      enable: false
+db:
+  center:
+    config: '{"jdbcUrl":"jdbc:mysql://120.26.64.82:3306/systemset4","username":"root","password":"123@bigdata","driverClassName":"com.mysql.cj.jdbc.Driver"}'
+  security:
+    config: '{"jdbcUrl":"jdbc:mysql://120.26.64.82:3306/uniauth","username":"root","password":"123@bigdata","driverClassName":"com.mysql.cj.jdbc.Driver"}'

+ 3 - 0
src/main/resources/application-hw.yml

@@ -1,7 +1,10 @@
 app:
+  enable-reset-config: true
   container:
     code: dev
   debug: true
+  singleton:
+    enable: true
   security:
     encrypt: false
     enable: false

+ 8 - 20
src/test/java/com/scbfkj/uni/library/JsonPathTest.java

@@ -1,28 +1,16 @@
 package com.scbfkj.uni.library;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.scbfkj.uni.system.ProcessUtil;
-import com.scbfkj.uni.utils.Util;
 import org.junit.jupiter.api.Test;
 
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.List;
-
 public class JsonPathTest {
     @Test
-    void test1() throws SocketException, UnknownHostException {
-        String mac = Util.mac();
-        System.out.println(mac);
-        List<ProcessUtil.AgorithmLibraryGroup> list = new ArrayList<>();
-        list.add(new ProcessUtil.AgorithmLibraryGroup("a",10));
-        list.add(new ProcessUtil.AgorithmLibraryGroup("a",10));
-        list.add(new ProcessUtil.AgorithmLibraryGroup("a",10));
-        list.add(new ProcessUtil.AgorithmLibraryGroup("a",10));
-        for (ProcessUtil.AgorithmLibraryGroup agorithmLibraryGroup : list.stream().distinct().toList()) {
-            System.out.println(agorithmLibraryGroup);
-        }
+    void test1() throws Exception {
+        String key = DataEncryptionUtil.encryptRSAByPublicKey("""
+{
+  "exp": "2099-12-31T23:59:59",
+  "mac": "FA:16:3E:95:3B:0B",
+  "key": "dataBase"
+}""");
+        System.out.println(key);
     }
 }

+ 25 - 31
src/test/java/com/scbfkj/uni/process/DataBaseTest.java

@@ -1,31 +1,25 @@
-//package com.scbfkj.uni.process;
-//
-//import org.junit.jupiter.api.Test;
-//
-//import java.util.List;
-//import java.util.Map;
-//
-//import static org.junit.jupiter.api.Assertions.*;
-//
-//class DataBaseTest {
-//
-//    String connection = """
-//                                {
-//                  "jdbcUrl": "jdbc:mysql://120.26.64.82:3306/systemset",
-//                  "username": "root",
-//                  "password": "123@bigdata",
-//                  "driverClassName": "com.mysql.cj.jdbc.Driver"
-//                }""";
-//    DataBase dataBase=new DataBase();
-//    @Test
-//    void getColumns() {
-//        List<Map<String, String>> serviceinfo = dataBase.getColumns(connection, "systemset","serviceinfo");
-//        System.out.println(serviceinfo);
-//    }
-//
-//    @Test
-//    void getTables() {
-//        List<String> systemset = dataBase.getTables(connection, "systemset");
-//        System.out.println(systemset);
-//    }
-//}
+package com.scbfkj.uni.process;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.Map;
+
+
+class DataBaseTest {
+
+    String connection = """
+                                {
+                  "jdbcUrl": "jdbc:mysql://120.26.64.82:3306/systemset3",
+                  "username": "root",
+                  "password": "123@bigdata",
+                  "driverClassName": "com.mysql.cj.jdbc.Driver"
+                }""";
+    DataBase dataBase=new DataBase();
+
+    @Test
+    void getTables() throws Exception {
+        List<Map<String, String>> systemset = dataBase.getColumnsByConnection(connection, "datasource");
+        System.out.println(systemset);
+    }
+}

+ 1 - 1
src/test/java/com/scbfkj/uni/process/IBMMQTest.java

@@ -34,7 +34,7 @@ class IBMMQTest {
         for (int i = 0; i < 100; i++) {
             strings.add("hello" + i);
         }
-        ibmmq.sendMessage(
+        ibmmq.sendSingletonMessage(
                 "120.26.64.82", 1414L, "DEV.ADMIN.SVRCONN", "QM1", "DEV.QUEUE.1", 1208L, "admin", "passw0rd", strings
         );
     }

+ 0 - 4
src/test/java/com/scbfkj/uni/process/KafkaTest.java

@@ -1,7 +1,5 @@
 package com.scbfkj.uni.process;
 
-import org.junit.jupiter.api.Test;
-
 import java.util.ArrayList;
 
 class KafkaTest {
@@ -12,7 +10,6 @@ class KafkaTest {
               "max.poll.records": "1000"
             }""";
 
-    @Test
     void receptionMessage() throws Exception {
 
         while (true) {
@@ -21,7 +18,6 @@ class KafkaTest {
         }
     }
 
-    @Test
     void sendMessage() throws Exception {
         while (true) {
             Kafka.sendMessage(config, "test01", new ArrayList<>() {{

+ 1 - 1
src/test/java/com/scbfkj/uni/process/RabbitMQTest.java

@@ -16,7 +16,7 @@ class RabbitMQTest {
         for (int i = 0; i < 100; i++) {
             strings.add("hello" + i);
         }
-        rabbitMQ.sendMessage("120.26.64.82", 5672L, "admin", "admin", "/", "bimTest", strings);
+        rabbitMQ.sendSingletonMessage("120.26.64.82", 5672L, "admin", "admin", "/", "bimTest", strings);
     }
 
     @Test

Some files were not shown because too many files changed in this diff