From 111c0e2c8dc015c9745eb2dfd3529a2585549c0e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=99=88=E5=BF=97=E6=B5=A9?=
<8583167+chen-zh@user.noreply.gitee.com>
Date: Wed, 22 Jul 2026 01:52:49 +0000
Subject: [PATCH] =?UTF-8?q?!84=20czh-20260717-=E4=BF=AE=E5=A4=8D-=E6=B5=8B?=
=?UTF-8?q?=E8=AF=95=E6=8E=A5=E5=8F=A3=E8=A1=A5=E5=85=85linkTitle=E5=8F=82?=
=?UTF-8?q?=E6=95=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* czh-20260717-修复-测试接口补充linkTitle参数
* czh-20260717-新增-sendMessage增加linkTitle参数
* czh-20260717-新增-sendMessage增加data参数支持
* czh-20260717-优化-去掉bizId和createDatetime字段
* czh-20260717-修复system-start缺少jeecg-module-im依赖
* czh-20260717-修复测试接口SSRF和日志泄漏问题
* czh-20260717-新增即时通消息推送模块及测试接口
---
jeecg-boot-module/jeecg-module-im/pom.xml | 21 +++
.../modules/ksim/client/KsimApiClient.java | 74 ++++++++++
.../modules/ksim/config/KsimProperties.java | 30 +++++
.../ksim/config/KsimScheduleConfig.java | 9 ++
.../ksim/controller/KsimTestController.java | 127 ++++++++++++++++++
.../jeecg/modules/ksim/dto/KsimApiResult.java | 32 +++++
.../modules/ksim/dto/KsimMsgSendDTO.java | 36 +++++
.../org/jeecg/modules/ksim/package-info.java | 1 +
.../ksim/service/IKsimMessageService.java | 14 ++
.../service/impl/KsimMessageServiceImpl.java | 61 +++++++++
.../modules/ksim/token/KsimTokenManager.java | 80 +++++++++++
jeecg-boot-module/pom.xml | 1 +
.../jeecg-system-start/pom.xml | 6 +
13 files changed, 492 insertions(+)
create mode 100644 jeecg-boot-module/jeecg-module-im/pom.xml
create mode 100644 jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/client/KsimApiClient.java
create mode 100644 jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/config/KsimProperties.java
create mode 100644 jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/config/KsimScheduleConfig.java
create mode 100644 jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/controller/KsimTestController.java
create mode 100644 jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/dto/KsimApiResult.java
create mode 100644 jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/dto/KsimMsgSendDTO.java
create mode 100644 jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/package-info.java
create mode 100644 jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/service/IKsimMessageService.java
create mode 100644 jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/service/impl/KsimMessageServiceImpl.java
create mode 100644 jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/token/KsimTokenManager.java
diff --git a/jeecg-boot-module/jeecg-module-im/pom.xml b/jeecg-boot-module/jeecg-module-im/pom.xml
new file mode 100644
index 0000000..e7e8a36
--- /dev/null
+++ b/jeecg-boot-module/jeecg-module-im/pom.xml
@@ -0,0 +1,21 @@
+
+
+
+ jeecg-boot-module
+ org.jeecgframework.boot
+ ${jeecgProjectVersion}
+
+ 4.0.0
+
+ jeecg-module-im
+
+
+
+ org.jeecgframework.boot
+ jeecg-boot-base-core
+
+
+
+
diff --git a/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/client/KsimApiClient.java b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/client/KsimApiClient.java
new file mode 100644
index 0000000..dd1c08c
--- /dev/null
+++ b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/client/KsimApiClient.java
@@ -0,0 +1,74 @@
+package org.jeecg.modules.ksim.client;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.util.RestUtil;
+import org.jeecg.modules.ksim.config.KsimProperties;
+import org.jeecg.modules.ksim.dto.KsimApiResult;
+import org.jeecg.modules.ksim.dto.KsimMsgSendDTO;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+@Slf4j
+@Component
+public class KsimApiClient {
+
+ @Resource
+ private KsimProperties ksimProperties;
+
+ private HttpHeaders jsonHeaders() {
+ return RestUtil.getHeaderApplicationJson();
+ }
+
+ public JSONObject createToken(String appId, String appSecret, int timeoutSeconds) {
+ JSONObject body = new JSONObject();
+ body.put("appId", appId);
+ body.put("appSecret", appSecret);
+ body.put("tokenTimeoutSeconds", timeoutSeconds);
+
+ String url = ksimProperties.getHost() + "/api-open/v1/token/create";
+ ResponseEntity resp = RestUtil.request(url, HttpMethod.POST, jsonHeaders(), null, body, JSONObject.class);
+
+ log.info("【即时通推送-Token创建】请求完成, appId: {}, 获取Token: {}",
+ appId, resp.getBody() != null && resp.getBody().getJSONObject("dataBody") != null ? "成功" : "失败");
+ return resp.getBody();
+ }
+
+ public JSONObject refreshToken(String oldToken, int timeoutSeconds) {
+ JSONObject body = new JSONObject();
+ body.put("tokenTimeoutSeconds", timeoutSeconds);
+
+ HttpHeaders headers = jsonHeaders();
+ headers.add("imOpenApiToken", oldToken);
+
+ String url = ksimProperties.getHost() + "/api-open/v1/token/refresh";
+ ResponseEntity resp = RestUtil.request(url, HttpMethod.POST, headers, null, body, JSONObject.class);
+
+ log.info("【即时通推送-Token刷新】请求完成, 获取Token: {}",
+ resp.getBody() != null && resp.getBody().getJSONObject("dataBody") != null ? "成功" : "失败");
+ return resp.getBody();
+ }
+
+ public KsimApiResult sendMsg(String token, KsimMsgSendDTO dto) {
+ HttpHeaders headers = jsonHeaders();
+ headers.add("imOpenApiToken", token);
+
+ String bodyJson = JSON.toJSONString(dto);
+ String url = ksimProperties.getHost() + "/api-open/v1/msg/send";
+
+ ResponseEntity resp = RestUtil.request(url, HttpMethod.POST, headers, null,
+ JSON.parseObject(bodyJson), JSONObject.class);
+
+ JSONObject respBody = resp.getBody();
+ int code = respBody != null ? respBody.getIntValue("code") : -1;
+ log.info("【即时通推送-消息发送】请求完成, toUser: {}, title: {}, code: {}",
+ dto.getToUserValue(), dto.getTitle(), code);
+
+ return respBody != null ? respBody.toJavaObject(KsimApiResult.class) : null;
+ }
+}
diff --git a/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/config/KsimProperties.java b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/config/KsimProperties.java
new file mode 100644
index 0000000..a133410
--- /dev/null
+++ b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/config/KsimProperties.java
@@ -0,0 +1,30 @@
+package org.jeecg.modules.ksim.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Component
+@ConfigurationProperties(prefix = "ksim")
+public class KsimProperties {
+
+ /** 即时通服务地址,如 http://10.2.0.54:19010 */
+ private String host = "http://10.2.0.54:19010";
+
+ /** 应用ID,在 application-{env}.yml 中配置 */
+ private String appId;
+
+ /** 应用密钥,在 application-{env}.yml 中配置 */
+ private String appSecret;
+
+ /** Token 有效期(秒),默认 7200(2小时) */
+ private int tokenTimeoutSeconds = 7200;
+
+ public String getHost() { return host; }
+ public void setHost(String host) { this.host = host; }
+ public String getAppId() { return appId; }
+ public void setAppId(String appId) { this.appId = appId; }
+ public String getAppSecret() { return appSecret; }
+ public void setAppSecret(String appSecret) { this.appSecret = appSecret; }
+ public int getTokenTimeoutSeconds() { return tokenTimeoutSeconds; }
+ public void setTokenTimeoutSeconds(int tokenTimeoutSeconds) { this.tokenTimeoutSeconds = tokenTimeoutSeconds; }
+}
diff --git a/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/config/KsimScheduleConfig.java b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/config/KsimScheduleConfig.java
new file mode 100644
index 0000000..9cb70e4
--- /dev/null
+++ b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/config/KsimScheduleConfig.java
@@ -0,0 +1,9 @@
+package org.jeecg.modules.ksim.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+@Configuration
+@EnableScheduling
+public class KsimScheduleConfig {
+}
diff --git a/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/controller/KsimTestController.java b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/controller/KsimTestController.java
new file mode 100644
index 0000000..4964f79
--- /dev/null
+++ b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/controller/KsimTestController.java
@@ -0,0 +1,127 @@
+package org.jeecg.modules.ksim.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.util.RestUtil;
+import org.jeecg.modules.ksim.dto.KsimMsgSendDTO;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
+import org.springframework.context.annotation.Profile;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+@Slf4j
+@RestController
+@Profile("dev")
+@RequestMapping("/ksim/test")
+public class KsimTestController {
+
+ @PostMapping("/send")
+ public Result