springboot对接钉钉,发送钉钉消息
通过以上步骤即可实现 Spring Boot 与钉钉的消息对接,建议根据实际业务需求选择适合的消息类型和安全策略。
2. 项目配置
2.1 application.yml 配置
bash
代码解读
复制代码
dingtalk: app: app-key: your_app_key app-secret: your_app_secret access-token-url: https://api.dingtalk.com/v1.0/oauth2/accessToken robot-webhook: https://oapi.dingtalk.com/robot/send
2.2 配置类
less
代码解读
复制代码
@Data @Configuration @ConfigurationProperties(prefix = "dingtalk.app") public class DingTalkConfig { private String appKey; private String appSecret; private String accessTokenUrl; private String robotWebhook; }
3. AccessToken 管理
3.1 带缓存的Token管理
ini
代码解读
复制代码
@Component public class DingTalkTokenManager { private static final Logger logger = LoggerFactory.getLogger(DingTalkTokenManager.class); @Autowired private DingTalkConfig config; @Autowired private RedisTemplate<String, String> redisTemplate; private static final String ACCESS_TOKEN_KEY = "dingtalk:access_token"; public String getAccessToken() { String token = redisTemplate.opsForValue().get(ACCESS_TOKEN_KEY); if (StringUtils.isNotBlank(token)) { return token; } return refreshAccessToken(); } private synchronized String refreshAccessToken() { String url = config.getAccessTokenUrl(); Map<String, String> params = new HashMap<>(); params.put("appKey", config.getAppKey()); params.put("appSecret", config.getAppSecret()); try { RestTemplate restTemplate = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity<Map<String, String>> request = new HttpEntity<>(params, headers); ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class); JsonObject json = JsonParser.parseString(response.getBody()).getAsJsonObject(); String newToken = json.get("accessToken").getAsString(); int expiresIn = json.get("expireIn").getAsInt(); redisTemplate.opsForValue().set( ACCESS_TOKEN_KEY, newToken, expiresIn - 300, // 提前5分钟过期 TimeUnit.SECONDS ); return newToken; } catch (Exception e) { logger.error("刷新钉钉Token失败", e); throw new RuntimeException("钉钉服务不可用"); } } }
4. 消息发送服务
4.1 通用消息发送基类
typescript
代码解读
复制代码
@Service public class DingTalkService { @Autowired private DingTalkConfig config; @Autowired private DingTalkTokenManager tokenManager; // 发送工作通知(需用户ID) public void sendToUser(String userId, String msg) { String accessToken = tokenManager.getAccessToken(); String url = "https://api.dingtalk.com/v1.0/robot/oToMessages/batchSend"; Map<String, Object> params = new HashMap<>(); params.put("robotCode", config.getAppKey()); params.put("userIds", Collections.singletonList(userId)); params.put("msgKey", "sampleText"); params.put("msgParam", "{"content":"" + msg + ""}"); sendRequest(url, accessToken, params); } // 发送群机器人消息(无需用户ID) public void sendRobotMessage(Object messageBody, String secret) { long timestamp = System.currentTimeMillis(); String sign = generateSign(timestamp, secret); String url = config.getRobotWebhook() + "?access_token=" + tokenManager.getAccessToken() + "×tamp=" + timestamp + "&sign=" + sign; sendRequest(url, null, messageBody); } private void sendRequest(String url, String token, Object params) { try { RestTemplate restTemplate = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); if (token != null) { headers.set("x-acs-dingtalk-access-token", token); } HttpEntity<Object> request = new HttpEntity<>(params, headers); ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class); handleResponse(response.getBody()); } catch (Exception e) { throw new RuntimeException("钉钉消息发送失败", e); } } // 生成加签(需要时使用) private String generateSign(Long timestamp, String secret) { 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(new String(Base64.getEncoder().encode(signData)), "UTF-8"); } private void handleResponse(String responseBody) { JsonObject json = JsonParser.parseString(responseBody).getAsJsonObject(); if (json.has("errcode") && json.get("errcode").getAsInt() != 0) { throw new RuntimeException("钉钉接口错误: " + responseBody); } } }
5. 消息类型封装
5.1 文本消息
typescript
代码解读
复制代码
public class TextMessage { private String msgtype = "text"; private TextContent text; private AtInfo at; public TextMessage(String content, List<String> atMobiles) { this.text = new TextContent(content); this.at = new AtInfo(atMobiles); } @Data @AllArgsConstructor private static class TextContent { private String content; } @Data @AllArgsConstructor private static class AtInfo { private List<String> atMobiles; private boolean isAtAll = false; } }
5.2 Markdown消息
arduino
代码解读
复制代码
public class MarkdownMessage { private String msgtype = "markdown"; private MarkdownContent markdown; private AtInfo at; public MarkdownMessage(String title, String text, List<String> atMobiles) { this.markdown = new MarkdownContent(title, text); this.at = new AtInfo(atMobiles); } @Data @AllArgsConstructor private static class MarkdownContent { private String title; private String text; } @Data @AllArgsConstructor private static class AtInfo { private List<String> atMobiles; private boolean isAtAll = false; } }
6. 控制器调用示例
less
代码解读
复制代码
@RestController @RequestMapping("/dingtalk") public class DingTalkController { @Autowired private DingTalkService dingTalkService; // 发送文本消息 @PostMapping("/send-text") public ResponseEntity<String> sendText(@RequestParam String userId) { dingTalkService.sendToUser(userId, "您的订单已处理完成"); return ResponseEntity.ok("消息已发送"); } // 发送机器人Markdown消息 @PostMapping("/send-markdown") public ResponseEntity<String> sendMarkdown(@RequestParam String secret) { MarkdownMessage message = new MarkdownMessage( "项目通知", "### 服务器状态告警\n> **CPU使用率**: 95%\n> **内存使用率**: 80%\n> 请及时处理!", Collections.singletonList("18812345678") ); dingTalkService.sendRobotMessage(message, secret); return ResponseEntity.ok("机器人消息已发送"); } }
7. 注意事项
-
消息类型限制:
- 单次消息最大长度:文本消息20000字符,Markdown消息5000字符
- 频率限制:每个机器人每分钟最多发送20条消息
-
安全策略:
- 推荐使用加签方式(与钉钉机器人设置一致)
- 敏感信息不要明文传输
-
用户识别:
- 通过手机号或用户ID发送需确保用户已在组织内
- 使用
userid需先通过钉钉API获取用户信息
-
错误代码处理:
- 300001:无效的access_token
- 310000:消息内容超过长度限制
- 330001:机器人被禁用
8. 高级功能扩展
-
消息卡片:
arduino
代码解读
复制代码
public class ActionCardMessage { private String msgtype = "actionCard"; private String title; private String text; private String singleTitle; private String singleURL; } -
异步消息:
typescript
代码解读
复制代码
@Async public void asyncSendMessage(String userId, String message) { dingTalkService.sendToUser(userId, message); } -
消息模板:
typescript
代码解读
复制代码
public class TemplateMessage { private String msgtype = "template"; private String templateId; private Map<String, String> data; }
9. 完整调用流程
- 获取用户ID(通过钉钉API或扫码登录)
- 选择消息类型并构造消息体
- 获取有效的access_token
- 调用钉钉消息接口发送
- 处理发送结果(成功/失败)
通过以上步骤即可实现 Spring Boot 与钉钉的消息对接,建议根据实际业务需求选择适合的消息类型和安全策略。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐



所有评论(0)