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> send(@RequestBody Map params) { + Map result = new LinkedHashMap<>(); + Map requestInfo = new LinkedHashMap<>(); + result.put("request", requestInfo); + + try { + String host = (String) params.getOrDefault("host", ""); + String appId = (String) params.getOrDefault("appId", ""); + String appSecret = (String) params.getOrDefault("appSecret", ""); + String toUserKeyType = (String) params.getOrDefault("toUserKeyType", ""); + String toUserValue = (String) params.getOrDefault("toUserValue", ""); + String title = (String) params.getOrDefault("title", ""); + String content = (String) params.getOrDefault("content", ""); + String linkUrl = (String) params.getOrDefault("linkUrl", ""); + String linkTitle = (String) params.getOrDefault("linkTitle", ""); + Object data = params.get("data"); + + // --- Step 1: 创建 Token --- + JSONObject tokenBody = new JSONObject(); + tokenBody.put("appId", appId); + tokenBody.put("appSecret", appSecret); + tokenBody.put("tokenTimeoutSeconds", 7200); + + String tokenUrl = host + "/api-open/v1/token/create"; + requestInfo.put("tokenRequestUrl", tokenUrl); + requestInfo.put("tokenRequestBody", tokenBody); + + ResponseEntity tokenResp = RestUtil.request( + tokenUrl, HttpMethod.POST, jsonHeaders(), null, tokenBody, JSONObject.class); + + JSONObject tokenRespBody = tokenResp.getBody(); + result.put("tokenResponse", tokenRespBody); + log.info("【即时通测试-Token创建】完成, 成功: {}", + tokenRespBody != null && tokenRespBody.getJSONObject("dataBody") != null); + + if (tokenRespBody == null || tokenRespBody.getJSONObject("dataBody") == null) { + result.put("success", false); + result.put("errorMessage", "Token 创建失败:响应为空"); + return Result.OK(result); + } + String token = tokenRespBody.getJSONObject("dataBody").getString("token"); + + // --- Step 2: 发送消息 --- + KsimMsgSendDTO dto = new KsimMsgSendDTO(); + dto.setToUserKeyType(toUserKeyType); + dto.setToUserValue(toUserValue); + dto.setTitle(title); + dto.setContent(content); + if (data != null) { + dto.setData(data); + } + if (linkTitle != null && !linkTitle.isEmpty()) { + dto.setLinkTitle(linkTitle); + } + if (linkUrl != null && !linkUrl.isEmpty()) { + dto.setLinkUrl(linkUrl); + dto.setLinkOpenMode("Web"); + } + + String msgUrl = host + "/api-open/v1/msg/send"; + requestInfo.put("msgRequestUrl", msgUrl); + requestInfo.put("msgRequestBody", dto); + + HttpHeaders msgHeaders = jsonHeaders(); + msgHeaders.add("imOpenApiToken", token); + + ResponseEntity msgResp = RestUtil.request( + msgUrl, HttpMethod.POST, msgHeaders, null, + JSON.parseObject(JSON.toJSONString(dto)), JSONObject.class); + + JSONObject msgRespBody = msgResp.getBody(); + result.put("msgResponse", msgRespBody); + log.info("【即时通测试-消息发送】完成, code: {}", + msgRespBody != null ? msgRespBody.getIntValue("code") : -1); + + if (msgRespBody != null) { + int code = msgRespBody.getIntValue("code"); + result.put("success", code == 0 || code == 200); + if (msgRespBody.getJSONObject("dataBody") != null) { + result.put("messageId", msgRespBody.getJSONObject("dataBody").getString("messageId")); + } + result.put("responseCode", code); + } else { + result.put("success", false); + result.put("errorMessage", "消息发送失败:响应为空"); + } + + } catch (Exception e) { + log.error("【即时通测试-发送】异常, error: {}", e.getMessage(), e); + result.put("success", false); + result.put("errorMessage", e.getMessage()); + } + + return Result.OK(result); + } + + private HttpHeaders jsonHeaders() { + return RestUtil.getHeaderApplicationJson(); + } +} diff --git a/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/dto/KsimApiResult.java b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/dto/KsimApiResult.java new file mode 100644 index 0000000..c86723d --- /dev/null +++ b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/dto/KsimApiResult.java @@ -0,0 +1,32 @@ +package org.jeecg.modules.ksim.dto; + +import com.alibaba.fastjson.annotation.JSONField; + +/** + * 即时通 API 通用响应体 + */ +public class KsimApiResult { + + private int code; + private String message; + private String timestamp; + private String requestId; + + @JSONField(name = "dataBody") + private T dataBody; + + public boolean isSuccess() { + return code == 0 || code == 200; + } + + public int getCode() { return code; } + public void setCode(int code) { this.code = code; } + public String getMessage() { return message; } + public void setMessage(String message) { this.message = message; } + public String getTimestamp() { return timestamp; } + public void setTimestamp(String timestamp) { this.timestamp = timestamp; } + public String getRequestId() { return requestId; } + public void setRequestId(String requestId) { this.requestId = requestId; } + public T getDataBody() { return dataBody; } + public void setDataBody(T dataBody) { this.dataBody = dataBody; } +} diff --git a/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/dto/KsimMsgSendDTO.java b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/dto/KsimMsgSendDTO.java new file mode 100644 index 0000000..e995553 --- /dev/null +++ b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/dto/KsimMsgSendDTO.java @@ -0,0 +1,36 @@ +package org.jeecg.modules.ksim.dto; + +/** + * 对应即时通文档 3.4.3 ReqMsgSendDTO + */ +public class KsimMsgSendDTO { + + private String title; + private String content; + private String toUserKeyType; + private String toUserValue; + private Object data; + private String dataFormat; + private String linkOpenMode; + private String linkTitle; + private String linkUrl; + + public String getTitle() { return title; } + public void setTitle(String title) { this.title = title; } + public String getContent() { return content; } + public void setContent(String content) { this.content = content; } + public String getToUserKeyType() { return toUserKeyType; } + public void setToUserKeyType(String toUserKeyType) { this.toUserKeyType = toUserKeyType; } + public String getToUserValue() { return toUserValue; } + public void setToUserValue(String toUserValue) { this.toUserValue = toUserValue; } + public Object getData() { return data; } + public void setData(Object data) { this.data = data; } + public String getDataFormat() { return dataFormat; } + public void setDataFormat(String dataFormat) { this.dataFormat = dataFormat; } + public String getLinkOpenMode() { return linkOpenMode; } + public void setLinkOpenMode(String linkOpenMode) { this.linkOpenMode = linkOpenMode; } + public String getLinkTitle() { return linkTitle; } + public void setLinkTitle(String linkTitle) { this.linkTitle = linkTitle; } + public String getLinkUrl() { return linkUrl; } + public void setLinkUrl(String linkUrl) { this.linkUrl = linkUrl; } +} diff --git a/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/package-info.java b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/package-info.java new file mode 100644 index 0000000..36cd72e --- /dev/null +++ b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/package-info.java @@ -0,0 +1 @@ +package org.jeecg.modules.ksim; diff --git a/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/service/IKsimMessageService.java b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/service/IKsimMessageService.java new file mode 100644 index 0000000..f7b33f0 --- /dev/null +++ b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/service/IKsimMessageService.java @@ -0,0 +1,14 @@ +package org.jeecg.modules.ksim.service; + +import org.jeecg.common.api.vo.Result; + +/** + * 即时通消息推送服务(对外唯一入口) + */ +public interface IKsimMessageService { + + Result sendMessage(String toUserKeyType, String toUserValue, + String title, String content, + String linkUrl, String linkTitle, + Object data); +} diff --git a/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/service/impl/KsimMessageServiceImpl.java b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/service/impl/KsimMessageServiceImpl.java new file mode 100644 index 0000000..4ab5eef --- /dev/null +++ b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/service/impl/KsimMessageServiceImpl.java @@ -0,0 +1,61 @@ +package org.jeecg.modules.ksim.service.impl; + +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.jeecg.common.api.vo.Result; +import org.jeecg.modules.ksim.client.KsimApiClient; +import org.jeecg.modules.ksim.dto.KsimApiResult; +import org.jeecg.modules.ksim.dto.KsimMsgSendDTO; +import org.jeecg.modules.ksim.service.IKsimMessageService; +import org.jeecg.modules.ksim.token.KsimTokenManager; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +@Slf4j +@Service +public class KsimMessageServiceImpl implements IKsimMessageService { + + @Resource + private KsimTokenManager tokenManager; + + @Resource + private KsimApiClient apiClient; + + @Override + public Result sendMessage(String toUserKeyType, String toUserValue, + String title, String content, + String linkUrl, String linkTitle, + Object data) { + String token = tokenManager.getToken(); + + KsimMsgSendDTO dto = new KsimMsgSendDTO(); + dto.setToUserKeyType(toUserKeyType); + dto.setToUserValue(toUserValue); + dto.setTitle(title); + dto.setContent(content); + dto.setData(data); + if (linkTitle != null && !linkTitle.isEmpty()) { + dto.setLinkTitle(linkTitle); + } + if (linkUrl != null && !linkUrl.isEmpty()) { + dto.setLinkUrl(linkUrl); + dto.setLinkOpenMode("Web"); + } + + KsimApiResult apiResult = apiClient.sendMsg(token, dto); + if (apiResult == null) { + log.error("【即时通推送-消息发送】响应为空, toUser: {}, title: {}", toUserValue, title); + return Result.error("即时通响应为空"); + } + if (!apiResult.isSuccess()) { + log.error("【即时通推送-消息发送】发送失败, code: {}, message: {}, toUser: {}, title: {}", + apiResult.getCode(), apiResult.getMessage(), toUserValue, title); + return Result.error(apiResult.getCode(), "即时通发送失败: " + apiResult.getMessage()); + } + + String messageId = apiResult.getDataBody() != null + ? apiResult.getDataBody().getString("messageId") : ""; + log.info("【即时通推送-消息发送】成功, messageId: {}, toUser: {}, title: {}", messageId, toUserValue, title); + return Result.OK(messageId); + } +} diff --git a/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/token/KsimTokenManager.java b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/token/KsimTokenManager.java new file mode 100644 index 0000000..d6b30b7 --- /dev/null +++ b/jeecg-boot-module/jeecg-module-im/src/main/java/org/jeecg/modules/ksim/token/KsimTokenManager.java @@ -0,0 +1,80 @@ +package org.jeecg.modules.ksim.token; + +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.jeecg.common.exception.JeecgBootException; +import org.jeecg.modules.ksim.client.KsimApiClient; +import org.jeecg.modules.ksim.config.KsimProperties; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.concurrent.TimeUnit; + +@Slf4j +@Component +public class KsimTokenManager { + + private static final String TOKEN_KEY = "ksim:token"; + + @Resource + private KsimProperties ksimProperties; + + @Resource + private KsimApiClient ksimApiClient; + + @Resource + private RedisTemplate redisTemplate; + + public String getToken() { + Object cached = redisTemplate.opsForValue().get(TOKEN_KEY); + if (cached != null) { + return cached.toString(); + } + return createAndCache(); + } + + @Scheduled(cron = "0 0 * * * ?") + public void refreshTask() { + log.info("【即时通推送-Token定时刷新】开始"); + try { + Object old = redisTemplate.opsForValue().get(TOKEN_KEY); + JSONObject result; + int timeout = ksimProperties.getTokenTimeoutSeconds(); + if (old != null) { + try { + result = ksimApiClient.refreshToken(old.toString(), timeout); + } catch (Exception e) { + log.warn("【即时通推送-Token定时刷新】刷新失败,回退到创建, error: {}", e.getMessage()); + result = ksimApiClient.createToken(ksimProperties.getAppId(), ksimProperties.getAppSecret(), timeout); + } + } else { + result = ksimApiClient.createToken(ksimProperties.getAppId(), ksimProperties.getAppSecret(), timeout); + } + cacheToken(result, timeout); + log.info("【即时通推送-Token定时刷新】完成"); + } catch (Exception e) { + log.error("【即时通推送-Token定时刷新】失败, error: {}", e.getMessage(), e); + } + } + + private String createAndCache() { + log.info("【即时通推送-Token懒加载】创建新Token"); + JSONObject result = ksimApiClient.createToken( + ksimProperties.getAppId(), ksimProperties.getAppSecret(), ksimProperties.getTokenTimeoutSeconds()); + return cacheToken(result, ksimProperties.getTokenTimeoutSeconds()); + } + + private String cacheToken(JSONObject result, int timeoutSeconds) { + if (result == null || result.getJSONObject("dataBody") == null) { + throw new JeecgBootException("【即时通推送】Token创建/刷新返回为空"); + } + JSONObject dataBody = result.getJSONObject("dataBody"); + String token = dataBody.getString("token"); + int ttl = Math.max(timeoutSeconds - 60, 60); + redisTemplate.opsForValue().set(TOKEN_KEY, token, ttl, TimeUnit.SECONDS); + log.info("【即时通推送-Token缓存】已写入Redis, ttl: {}s", ttl); + return token; + } +} diff --git a/jeecg-boot-module/pom.xml b/jeecg-boot-module/pom.xml index 2c00b83..364b0ad 100644 --- a/jeecg-boot-module/pom.xml +++ b/jeecg-boot-module/pom.xml @@ -20,6 +20,7 @@ jeecg-boot-module-airag jeecg-module-flow jeecg-module-tools + jeecg-module-im diff --git a/jeecg-module-system/jeecg-system-start/pom.xml b/jeecg-module-system/jeecg-system-start/pom.xml index 21d84d9..b590de8 100644 --- a/jeecg-module-system/jeecg-system-start/pom.xml +++ b/jeecg-module-system/jeecg-system-start/pom.xml @@ -27,6 +27,12 @@ org.jeecgframework.boot jeecg-module-supervision + + + org.jeecgframework.boot + jeecg-module-im + ${jeecgProjectVersion} + org.jeecgframework.boot jeecg-module-flow