钉钉机器人配置文档
https://developers.dingtalk.com/document/robots/custom-robot-access
安装
<!-- 钉钉 -->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>alibaba-dingtalk-service-sdk</artifactId>
<version>2.0.0</version>
</dependency>
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.tomcat.util.codec.binary.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
/**
* 发送钉钉消息
*
* @author jason
*/
@Slf4j
public class DingTalkHelper {
// 钉钉群名:【告警群】开票失败
private static final String ROBOT_URL = "https://oapi.dingtalk.com/robot/send?access_token=";
private static final String ROBOT_TOKEN = "xxx";
private static final String ROBOT_SECRET = "xxx";
/**
* 发送普通文本消息
*/
public static void sendMsg(String textMsg) {
try {
Long timestamp = System.currentTimeMillis();
String sign = generateSign(timestamp);
DingTalkClient client = new DefaultDingTalkClient(ROBOT_URL + ROBOT_TOKEN + "×tamp=" + timestamp + "&sign=" + sign);
OapiRobotSendRequest request = new OapiRobotSendRequest();
request.setMsgtype("text");
OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text();
text.setContent(textMsg);
request.setText(text);
OapiRobotSendRequest.At at = new OapiRobotSendRequest.At();
// 单独@人
// at.setAtMobiles(Arrays.asList("手机号"));
at.setIsAtAll(true);
request.setAt(at);
OapiRobotSendResponse response = client.execute(request);
log.info("钉钉机器人发送文本消息结果:{}, code:{}, msg:{}", response.isSuccess(), response.getErrcode(), response.getErrmsg());
} catch (Exception e) {
log.error("钉钉机器人发送文本消息异常", e);
}
}
/**
* 签名
*/
private static String generateSign(Long timestamp) {
try {
String stringToSign = timestamp + "\n" + ROBOT_SECRET;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(ROBOT_SECRET.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
return URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
} catch (Exception e) {
log.error("钉钉机器人获取签名异常", e);
return null;
}
}
public static void main(String[] args) {
DingTalkHelper.sendMsg("测试文本消息");
}
}
解决钉钉限流
由于钉钉消息最大限制:1分钟/20条消息。这里开个线程池,统一处理这些消息,并限制发送的频率
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 发送钉钉消息-限流方案
*
* @author jason
*/
@Slf4j
public class DingTalkSentinel {
// 10个核心线程数,队列大小限制1000,超了直接抛异常
private static final ExecutorService executor = new ThreadPoolExecutor(10, 10,
0L, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<>(1000));
public static class ThreadTask implements Runnable {
private final String textMsg;
public ThreadTask(String textMsg) {
this.textMsg = textMsg;
}
@SneakyThrows
public void run() {
// 钉钉机器人频率限制:1分钟/20条消息
DingTalkHelper.sendMsg(textMsg);
log.info(textMsg);
TimeUnit.SECONDS.sleep(31);
}
}
@SneakyThrows
public static void sendMsg(String textMsg) {
executor.execute(new ThreadTask(textMsg));
}
public static void main(String[] args) {
int threadCount = 21;
for (int i = 0; i < threadCount; i++) {
DingTalkSentinel.sendMsg("测试钉钉限速:" + i);
}
}
}