添加钉钉机器人
This commit is contained in:
@@ -7,8 +7,11 @@ import com.corewing.app.common.Result;
|
|||||||
import com.corewing.app.dto.FeedbackRequest;
|
import com.corewing.app.dto.FeedbackRequest;
|
||||||
import com.corewing.app.entity.AppFeedback;
|
import com.corewing.app.entity.AppFeedback;
|
||||||
import com.corewing.app.service.AppFeedbackService;
|
import com.corewing.app.service.AppFeedbackService;
|
||||||
|
import com.corewing.app.util.DingTalkUtil;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -19,9 +22,11 @@ import java.util.List;
|
|||||||
public class AppFeedbackController {
|
public class AppFeedbackController {
|
||||||
|
|
||||||
private final AppFeedbackService feedbackService;
|
private final AppFeedbackService feedbackService;
|
||||||
|
private final DingTalkUtil dingTalkUtil;
|
||||||
|
|
||||||
public AppFeedbackController(AppFeedbackService feedbackService) {
|
public AppFeedbackController(AppFeedbackService feedbackService, DingTalkUtil dingTalkUtil) {
|
||||||
this.feedbackService = feedbackService;
|
this.feedbackService = feedbackService;
|
||||||
|
this.dingTalkUtil = dingTalkUtil;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,6 +52,8 @@ public class AppFeedbackController {
|
|||||||
|
|
||||||
boolean success = feedbackService.createFeedback(feedback);
|
boolean success = feedbackService.createFeedback(feedback);
|
||||||
if (success) {
|
if (success) {
|
||||||
|
// 推送到钉钉
|
||||||
|
sendFeedbackToDingTalk(feedback);
|
||||||
return Result.success("反馈提交成功");
|
return Result.success("反馈提交成功");
|
||||||
}
|
}
|
||||||
return Result.error("反馈提交失败");
|
return Result.error("反馈提交失败");
|
||||||
@@ -142,4 +149,53 @@ public class AppFeedbackController {
|
|||||||
return Result.error(e.getMessage());
|
return Result.error(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送反馈信息到钉钉
|
||||||
|
*/
|
||||||
|
private void sendFeedbackToDingTalk(AppFeedback feedback) {
|
||||||
|
try {
|
||||||
|
String title = "📢 新的用户反馈";
|
||||||
|
StringBuilder text = new StringBuilder();
|
||||||
|
text.append("### 📢 新的用户反馈\n\n");
|
||||||
|
text.append("---\n\n");
|
||||||
|
|
||||||
|
// 用户信息
|
||||||
|
if (feedback.getUserId() != null) {
|
||||||
|
text.append("**用户ID:** ").append(feedback.getUserId()).append("\n\n");
|
||||||
|
} else {
|
||||||
|
text.append("**用户ID:** 匿名用户\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 反馈类型
|
||||||
|
text.append("**问题类型:** ").append(feedback.getFeedbackType()).append("\n\n");
|
||||||
|
|
||||||
|
// 反馈标题
|
||||||
|
text.append("**问题标题:** ").append(feedback.getTitle()).append("\n\n");
|
||||||
|
|
||||||
|
// 反馈内容
|
||||||
|
if (feedback.getContent() != null && !feedback.getContent().trim().isEmpty()) {
|
||||||
|
text.append("**问题描述:** \n\n").append(feedback.getContent()).append("\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 联系方式
|
||||||
|
if (feedback.getContact() != null && !feedback.getContact().trim().isEmpty()) {
|
||||||
|
text.append("**联系方式:** ").append(feedback.getContact()).append("\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交时间
|
||||||
|
text.append("**提交时间:** ").append(
|
||||||
|
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
|
||||||
|
).append("\n\n");
|
||||||
|
|
||||||
|
text.append("---\n\n");
|
||||||
|
text.append("> 请及时处理用户反馈!");
|
||||||
|
|
||||||
|
// 异步发送钉钉消息(避免阻塞用户请求)
|
||||||
|
new Thread(() -> dingTalkUtil.sendMarkdownMessage(title, text.toString())).start();
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 钉钉推送失败不影响反馈提交,只记录日志
|
||||||
|
// log.error("推送反馈到钉钉失败: {}", e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
164
src/main/java/com/corewing/app/util/DingTalkUtil.java
Normal file
164
src/main/java/com/corewing/app/util/DingTalkUtil.java
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
package com.corewing.app.util;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 钉钉机器人推送工具类
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class DingTalkUtil {
|
||||||
|
|
||||||
|
@Value("${dingtalk.webhook:}")
|
||||||
|
private String webhook;
|
||||||
|
|
||||||
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送文本消息到钉钉
|
||||||
|
*
|
||||||
|
* @param content 消息内容
|
||||||
|
* @return 是否发送成功
|
||||||
|
*/
|
||||||
|
public boolean sendTextMessage(String content) {
|
||||||
|
return sendTextMessage(content, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送文本消息到钉钉
|
||||||
|
*
|
||||||
|
* @param content 消息内容
|
||||||
|
* @param atMobiles 需要@的手机号列表
|
||||||
|
* @return 是否发送成功
|
||||||
|
*/
|
||||||
|
public boolean sendTextMessage(String content, String[] atMobiles) {
|
||||||
|
if (webhook == null || webhook.trim().isEmpty()) {
|
||||||
|
log.warn("钉钉 Webhook 未配置,跳过消息推送");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Map<String, Object> message = new HashMap<>();
|
||||||
|
message.put("msgtype", "text");
|
||||||
|
|
||||||
|
Map<String, Object> text = new HashMap<>();
|
||||||
|
text.put("content", content);
|
||||||
|
message.put("text", text);
|
||||||
|
|
||||||
|
// @人员配置
|
||||||
|
if (atMobiles != null && atMobiles.length > 0) {
|
||||||
|
Map<String, Object> at = new HashMap<>();
|
||||||
|
at.put("atMobiles", atMobiles);
|
||||||
|
at.put("isAtAll", false);
|
||||||
|
message.put("at", at);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sendRequest(message);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("发送钉钉文本消息失败: {}", e.getMessage(), e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送 Markdown 消息到钉钉
|
||||||
|
*
|
||||||
|
* @param title 消息标题
|
||||||
|
* @param text Markdown 内容
|
||||||
|
* @return 是否发送成功
|
||||||
|
*/
|
||||||
|
public boolean sendMarkdownMessage(String title, String text) {
|
||||||
|
return sendMarkdownMessage(title, text, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送 Markdown 消息到钉钉
|
||||||
|
*
|
||||||
|
* @param title 消息标题
|
||||||
|
* @param text Markdown 内容
|
||||||
|
* @param atMobiles 需要@的手机号列表
|
||||||
|
* @return 是否发送成功
|
||||||
|
*/
|
||||||
|
public boolean sendMarkdownMessage(String title, String text, String[] atMobiles) {
|
||||||
|
if (webhook == null || webhook.trim().isEmpty()) {
|
||||||
|
log.warn("钉钉 Webhook 未配置,跳过消息推送");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Map<String, Object> message = new HashMap<>();
|
||||||
|
message.put("msgtype", "markdown");
|
||||||
|
|
||||||
|
Map<String, Object> markdown = new HashMap<>();
|
||||||
|
markdown.put("title", title);
|
||||||
|
markdown.put("text", text);
|
||||||
|
message.put("markdown", markdown);
|
||||||
|
|
||||||
|
// @人员配置
|
||||||
|
if (atMobiles != null && atMobiles.length > 0) {
|
||||||
|
Map<String, Object> at = new HashMap<>();
|
||||||
|
at.put("atMobiles", atMobiles);
|
||||||
|
at.put("isAtAll", false);
|
||||||
|
message.put("at", at);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sendRequest(message);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("发送钉钉 Markdown 消息失败: {}", e.getMessage(), e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送 HTTP 请求到钉钉机器人
|
||||||
|
*
|
||||||
|
* @param message 消息体
|
||||||
|
* @return 是否发送成功
|
||||||
|
*/
|
||||||
|
private boolean sendRequest(Map<String, Object> message) {
|
||||||
|
HttpURLConnection connection = null;
|
||||||
|
try {
|
||||||
|
URL url = new URL(webhook);
|
||||||
|
connection = (HttpURLConnection) url.openConnection();
|
||||||
|
connection.setRequestMethod("POST");
|
||||||
|
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
|
||||||
|
connection.setDoOutput(true);
|
||||||
|
connection.setConnectTimeout(5000);
|
||||||
|
connection.setReadTimeout(5000);
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
String jsonMessage = objectMapper.writeValueAsString(message);
|
||||||
|
try (OutputStream os = connection.getOutputStream()) {
|
||||||
|
byte[] input = jsonMessage.getBytes(StandardCharsets.UTF_8);
|
||||||
|
os.write(input, 0, input.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取响应
|
||||||
|
int responseCode = connection.getResponseCode();
|
||||||
|
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||||
|
log.info("钉钉消息推送成功");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
log.error("钉钉消息推送失败, HTTP 状态码: {}", responseCode);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("钉钉消息推送异常: {}", e.getMessage(), e);
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
if (connection != null) {
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -79,3 +79,7 @@ spring.mail.properties.mail.smtp.ssl.required=true
|
|||||||
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
|
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
|
||||||
spring.mail.properties.mail.smtp.socketFactory.port=465
|
spring.mail.properties.mail.smtp.socketFactory.port=465
|
||||||
spring.mail.properties.mail.smtp.socketFactory.fallback=false
|
spring.mail.properties.mail.smtp.socketFactory.fallback=false
|
||||||
|
|
||||||
|
# 钉钉机器人配置
|
||||||
|
# 请前往钉钉群设置 -> 智能群助手 -> 添加机器人 -> 自定义机器人,获取 Webhook 地址
|
||||||
|
dingtalk.webhook=https://oapi.dingtalk.com/robot/send?access_token=7eed4b3483303c9ec71ef37a08c347bb597fd4c64211a96a8f55f72405ff6444
|
||||||
|
|||||||
Reference in New Issue
Block a user