From 91ff09eeff2d555b03b9502122cfec77136e2f3e Mon Sep 17 00:00:00 2001 From: zhoujinhua Date: Tue, 21 Oct 2025 09:17:51 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=92=89=E9=92=89=E6=9C=BA?= =?UTF-8?q?=E5=99=A8=E4=BA=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/controller/AppFeedbackController.java | 21 ++++++++ .../com/corewing/app/util/DingTalkUtil.java | 54 +++++++++++++++++-- src/main/resources/application.properties | 4 +- 3 files changed, 75 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/corewing/app/controller/AppFeedbackController.java b/src/main/java/com/corewing/app/controller/AppFeedbackController.java index 54f603c..61e90b7 100644 --- a/src/main/java/com/corewing/app/controller/AppFeedbackController.java +++ b/src/main/java/com/corewing/app/controller/AppFeedbackController.java @@ -150,6 +150,27 @@ public class AppFeedbackController { } } + /** + * 测试钉钉推送 + */ + @GetMapping("/test-dingtalk") + public Result testDingTalk() { + try { + String title = "测试消息"; + String text = "### 🔔 钉钉推送测试\n\n这是一条测试消息,用于验证钉钉推送功能是否正常工作。\n\n**测试时间:** " + + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + + boolean success = dingTalkUtil.sendMarkdownMessage(title, text); + if (success) { + return Result.success("钉钉推送测试成功,请检查钉钉群消息"); + } else { + return Result.error("钉钉推送测试失败,请检查配置和日志"); + } + } catch (Exception e) { + return Result.error("测试异常: " + e.getMessage()); + } + } + /** * 发送反馈信息到钉钉 */ diff --git a/src/main/java/com/corewing/app/util/DingTalkUtil.java b/src/main/java/com/corewing/app/util/DingTalkUtil.java index b5e74c4..869de2e 100644 --- a/src/main/java/com/corewing/app/util/DingTalkUtil.java +++ b/src/main/java/com/corewing/app/util/DingTalkUtil.java @@ -5,10 +5,14 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; +import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import java.util.Base64; import java.util.HashMap; import java.util.Map; @@ -22,6 +26,9 @@ public class DingTalkUtil { @Value("${dingtalk.webhook:}") private String webhook; + @Value("${dingtalk.secret:}") + private String secret; + private static final ObjectMapper objectMapper = new ObjectMapper(); /** @@ -119,6 +126,20 @@ public class DingTalkUtil { } } + /** + * 生成钉钉签名 + * + * @param timestamp 时间戳 + * @return 签名 + */ + private String generateSign(long timestamp) throws Exception { + String stringToSign = timestamp + "\n" + secret; + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256")); + byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8)); + return URLEncoder.encode(Base64.getEncoder().encodeToString(signData), "UTF-8"); + } + /** * 发送 HTTP 请求到钉钉机器人 * @@ -128,7 +149,17 @@ public class DingTalkUtil { private boolean sendRequest(Map message) { HttpURLConnection connection = null; try { - URL url = new URL(webhook); + String finalWebhook = webhook; + + // 如果配置了 secret,需要添加签名 + if (secret != null && !secret.trim().isEmpty()) { + long timestamp = System.currentTimeMillis(); + String sign = generateSign(timestamp); + finalWebhook = webhook + "×tamp=" + timestamp + "&sign=" + sign; + log.info("使用加签模式,timestamp: {}", timestamp); + } + + URL url = new URL(finalWebhook); connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); @@ -138,6 +169,8 @@ public class DingTalkUtil { // 发送请求 String jsonMessage = objectMapper.writeValueAsString(message); + log.info("发送钉钉消息: {}", jsonMessage); + try (OutputStream os = connection.getOutputStream()) { byte[] input = jsonMessage.getBytes(StandardCharsets.UTF_8); os.write(input, 0, input.length); @@ -145,11 +178,26 @@ public class DingTalkUtil { // 读取响应 int responseCode = connection.getResponseCode(); + + // 读取响应体(包含错误信息) + java.io.BufferedReader br = new java.io.BufferedReader( + new java.io.InputStreamReader( + responseCode >= 400 ? connection.getErrorStream() : connection.getInputStream(), + StandardCharsets.UTF_8 + ) + ); + StringBuilder response = new StringBuilder(); + String responseLine; + while ((responseLine = br.readLine()) != null) { + response.append(responseLine.trim()); + } + br.close(); + if (responseCode == HttpURLConnection.HTTP_OK) { - log.info("钉钉消息推送成功"); + log.info("钉钉消息推送成功, 响应: {}", response.toString()); return true; } else { - log.error("钉钉消息推送失败, HTTP 状态码: {}", responseCode); + log.error("钉钉消息推送失败, HTTP 状态码: {}, 响应: {}", responseCode, response.toString()); return false; } } catch (Exception e) { diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 3ff91fe..f010108 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -81,5 +81,7 @@ spring.mail.properties.mail.smtp.socketFactory.port=465 spring.mail.properties.mail.smtp.socketFactory.fallback=false # 钉钉机器人配置 -# 请前往钉钉群设置 -> 智能群助手 -> 添加机器人 -> 自定义机器人,获取 Webhook 地址 +# 请前往钉钉群设置 -> 智能群助手 -> 添加机器人 -> 自定义机器人,获取 Webhook 地址和密钥 dingtalk.webhook=https://oapi.dingtalk.com/robot/send?access_token=7eed4b3483303c9ec71ef37a08c347bb597fd4c64211a96a8f55f72405ff6444 +# 如果使用加签安全设置,请填写密钥(secret) +dingtalk.secret=SEC0f2b835f28139905e3c0b5be979b215df1735f1154f36514aafbae8708014148