package com.xcong.excoin.utils.dingtalk; import com.dingtalk.api.DefaultDingTalkClient; import com.dingtalk.api.DingTalkClient; import com.dingtalk.api.request.OapiRobotSendRequest; import com.dingtalk.api.response.OapiRobotSendResponse; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Base64; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; /** * 钉钉群机器人消息发送工具。 * *

快速使用

*
 * // 1. 创建发送器
 * DingTalkRobot robot = new DingTalkRobot(accessToken, secret);
 *
 * // 2a. 发送文本
 * robot.sendText("充值到账:1000 USDT");
 *
 * // 2b. 发送 Markdown(title 会作为 @所有人 通知标题)
 * robot.sendMarkdown("策略通知", "## 盈亏汇总\n- 已实现: **+2.5 USDT**");
 *
 * // 2c. 发送 ActionCard
 * robot.sendActionCard("止盈通知", "策略已达止盈目标", "查看详情", "https://xxx.com");
 * 
* * @author wzy */ @Slf4j public class DingTalkUtils { private static final String ROBOT_URL = "https://oapi.dingtalk.com/robot/send?access_token="; private final String accessToken; private final String secret; // ==================== 默认实例(向后兼容旧代码) ==================== private static volatile DingTalkUtils DEFAULT; public static DingTalkUtils getDefault() { if (DEFAULT == null) { synchronized (DingTalkUtils.class) { if (DEFAULT == null) { // DEFAULT = new DingTalkUtils( // "57a3e695f78d7547fe20fb7aef82cf35a27de1846bbc6966e0194761976d7597", // "SECd59a93c8939eeaef0d97b5b714639df4af95d922002d0a440bc82ad42710a89e"); DEFAULT = new DingTalkUtils( "e357a3417991da86a5f79ea5bc8785b529c1da8b9d27458febed3b3d10c857c4", "SECf2b819e930cb4b367cf599f11a30eb8a5d0f4b0b1c069a57aa15328a3feebf8c"); } } } return DEFAULT; } /** * 向后兼容:按类型代码发送 ActionCard 通知。 * * @param typeIndex {@link DingTalkType} 的 index */ public static void sendActionCard(int typeIndex) { DingTalkType dt = DingTalkType.byIndex(typeIndex); if (dt == null) { log.warn("[DingTalk] 未知通知类型: {}", typeIndex); return; } getDefault().sendActionCard(dt.getName(), dt.getName(), "查看详情", "http://baidu.com"); } // ==================== 构造 ==================== /** * @param accessToken 钉钉机器人 Webhook 地址中的 access_token * @param secret 钉钉机器人安全设置中的加签密钥 */ public DingTalkUtils(String accessToken, String secret) { this.accessToken = accessToken; this.secret = secret; } // ==================== 文本消息 ==================== /** * 发送纯文本消息。 * * @param content 文本内容,最大 4096 字节,支持 @手机号 提醒 */ public void sendText(String content) { OapiRobotSendRequest req = new OapiRobotSendRequest(); req.setMsgtype("text"); OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text(); text.setContent(content); req.setText(text); execute(req); } // ==================== Markdown 消息 ==================== /** * 发送 Markdown 消息。 * * @param title 消息标题,显示在会话列表和推送通知中 * @param markdown Markdown 正文,支持标题/加粗/链接/列表等语法 */ public void sendMarkdown(String title, String markdown) { OapiRobotSendRequest req = new OapiRobotSendRequest(); req.setMsgtype("markdown"); OapiRobotSendRequest.Markdown md = new OapiRobotSendRequest.Markdown(); md.setTitle(title); md.setText(markdown); req.setMarkdown(md); execute(req); } // ==================== ActionCard 消息 ==================== /** * 发送单按钮 ActionCard 消息。 * * @param title 卡片标题 * @param text 卡片正文(支持 Markdown,减号开头的行会被转为列表) * @param btnTitle 按钮文字 * @param btnUrl 按钮跳转链接 */ public void sendActionCard(String title, String text, String btnTitle, String btnUrl) { OapiRobotSendRequest req = new OapiRobotSendRequest(); req.setMsgtype("actionCard"); OapiRobotSendRequest.Actioncard card = new OapiRobotSendRequest.Actioncard(); card.setTitle(title); card.setText(text); card.setBtnOrientation("1"); List btns = new ArrayList<>(); OapiRobotSendRequest.Btns btn = new OapiRobotSendRequest.Btns(); btn.setTitle(btnTitle); btn.setActionURL(btnUrl); btns.add(btn); card.setBtns(btns); req.setActionCard(card); execute(req); } // ==================== 内部执行 ==================== private void execute(OapiRobotSendRequest request) { try { Long timestamp = System.currentTimeMillis(); String sign = generateSign(timestamp); String url = ROBOT_URL + accessToken + "×tamp=" + timestamp + "&sign=" + sign; DingTalkClient client = new DefaultDingTalkClient(url); OapiRobotSendResponse response = client.execute(request); if (!response.isSuccess()) { log.warn("[DingTalk] 发送失败, errcode:{}, errmsg:{}", response.getErrcode(), response.getErrmsg()); } else { log.info("[DingTalk] 发送成功"); } } catch (Exception e) { log.error("[DingTalk] 发送异常", e); } } private String generateSign(Long timestamp) throws Exception { String stringToSign = timestamp + "\n" + secret; Mac mac = Mac.getInstance("HmacSHA256"); mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256")); byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8")); return URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8"); } public static void main(String[] args) { DingTalkUtils.getDefault().sendActionCard("风险提示", "测试123", "", ""); } }