封装钉钉群机器人 Webhook API,支持三种消息类型:**文本**(text)、**Markdown**、**ActionCard(卡片+按钮)**。
文件位置:
- com.xcong.excoin.utils.dingtalk.DingTalkUtils — 消息发送核心类
- com.xcong.excoin.utils.dingtalk.DingTalkType — 通知类型枚举
依赖:taobao-sdk-java.jar(本地 jar,已配置在 lib/ 目录下)
DingTalkUtils robot = new DingTalkUtils(accessToken, secret);
参数说明:
| 参数 | 来源 |
|------|------|
| accessToken | 机器人 Webhook URL 中 access_token= 后面的部分 |
| secret | 机器人安全设置 → 加签 → 密钥(勾选后才需要) |
机器人创建步骤:群设置 → 智能群助手 → 添加机器人 → 自定义 → 安全设置选"加签" → 复制 Webhook URL 和密钥。
robot.sendText("充值到账通知:用户123 充值 1000 USDT");
robot.sendMarkdown("策略止盈通知",
"## 网格策略止盈\n" +
"- 累计盈亏: **+2.5 USDT**\n" +
"- 当前价格: 3450.12\n" +
"- 触发时间: 15:30:00");
robot.sendActionCard(
"止盈通知", // 标题
"### 策略已达到止盈目标\n" + // 正文(支持 Markdown)
"- 累计盈亏: **+5.0 USDT**\n" +
"- 策略已自动停止",
"查看详情", // 按钮文字
"https://your-site.com/strategy/detail" // 跳转链接
);
| 签名 | 说明 |
|---|---|
DingTalkUtils(accessToken, secret) |
创建发送器实例 |
| 方法 | 说明 |
|---|---|
sendText(content) |
发送纯文本,最长 4096 字节 |
sendMarkdown(title, markdown) |
发送 Markdown,title 显示在推送通知栏 |
sendActionCard(title, text, btnTitle, btnUrl) |
发送带按钮的卡片消息 |
| 方法 | 说明 |
|---|---|
DingTalkUtils.getDefault() |
获取使用默认密钥的静态实例 |
DingTalkUtils.sendActionCard(int typeIndex) |
按 DingTalkType 索引发送 ActionCard |
public enum DingTalkType {
PAY_CONFIRM("充值确认", 1),
FAST_SALE("快速卖出", 2),
TI_COIN("提币通知", 3),
CARD_VERIFY("实名认证", 4),
BLOCK_COIN("链上转账通知", 5);
}
| 方法 | 说明 |
|---|---|
getName() |
获取通知名称 |
getIndex() |
获取类型索引 |
DingTalkType.byIndex(int) |
按索引查找枚举值 |
// 在 GateGridTradeService 中注入 DingTalkUtils
private final DingTalkUtils dingTalk;
public GateGridTradeService(GateConfig config, DingTalkUtils dingTalk) {
this.config = config;
this.dingTalk = dingTalk;
// ...
}
// 止盈时通知
public void onPositionClose(...) {
if (totalPnl.compareTo(config.getOverallTp()) >= 0) {
dingTalk.sendMarkdown("策略止盈",
"## 网格策略已止盈\n" +
"- 合约: " + config.getContract() + "\n" +
"- 累计盈亏: **" + cumulativePnl + " USDT**\n" +
"- 浮动盈亏: " + unrealizedPnl + " USDT");
state = StrategyState.STOPPED;
}
}
// 止损通知
if (totalPnl.compareTo(config.getMaxLoss().negate()) <= 0) {
dingTalk.sendText("‼ 策略亏损预警: " + totalPnl + " USDT,已停止");
state = StrategyState.STOPPED;
}
@Configuration
public class DingTalkConfig {
@Value("${dingtalk.access-token}")
private String accessToken;
@Value("${dingtalk.secret}")
private String secret;
@Bean
public DingTalkUtils dingTalkUtils() {
return new DingTalkUtils(accessToken, secret);
}
}
application.yml:yaml dingtalk: access-token: 161d5e5b60ae5d6b4c80f2a9c35f9f212961a7c7154aa7e94b99503eca3886b0 secret: SECc0b73559742b950f07eabbd050c406a6abb3b67d112d3735289e90f58884c543
以下旧写法仍然有效:
// ThreadPoolUtils 中的旧调用,无需修改
ThreadPoolUtils.sendDingTalk(5); // → 发送"链上转账通知" ActionCard
| 维度 | 旧版 | 新版 |
|---|---|---|
| 消息类型 | 仅 ActionCard | text / markdown / actionCard |
| 密钥配置 | 硬编码 | 构造器注入,可任意实例化 |
| 代码量 | 67 行 | 133 行 |
| API 灵活度 | 只能按 type index 发 | 自由组合 title/text/button |
| 错误处理 | log.error 全部情况 |
区分失败/异常,记录 errcode |
| 旧版兼容 | — | sendActionCard(int) 仍可用 |