效果

 

 

 

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
public class DingMsgService {

    @Value("${config.dingtalk.secret}")
    private String dingtalkSecret;

    @Value("${config.dingtalk.webhook}")
    private String dingtalkWebhook;

    public void sendDingTalkMsg(Exception ex, String requestURI) {
        StringBuilder builder = StrUtil.builder();
        builder.append("发生时间:[" + DateUtil.now() + "]\n");
        builder.append("发生环境:[" + SpringUtil.getActiveProfile() + "]\n");
        builder.append("请求地址:[" + requestURI + "]\n");
        builder.append("异常信息:[" + ExceptionUtil.getMessage(ex) + "]\n");
        StackTraceElement[] stackTrace = ex.getStackTrace();
        for (StackTraceElement element : stackTrace) {
            if (!element.getClassName().contains("yunkeji")) {
                continue;
            }
            builder.append(
                    element.getFileName()
                            + "#"
                            + element.getMethodName()
                            + "#"
                            + element.getLineNumber()
                            + "\n");
        }
        String content = builder.toString();
        // 钉钉最大只能发送2000个字符
        if (content.length() >= 1990) {
            content = content.substring(0, 1990);
        }
        DingTalkSendMsgRequestDTO requestDTO = new DingTalkSendMsgRequestDTO();
        requestDTO.setSecret(dingtalkSecret);
        requestDTO.setWebhook(dingtalkWebhook);
        requestDTO.setContent(content);

        // 消息内容
        Map<String, String> contentMap = new HashMap<>();
        contentMap.put("content", requestDTO.getContent());
        // 通知人
        Map<String, Object> atMap = new HashMap<>();
        // 1.是否通知所有人
        atMap.put("isAtAll", true);
        // 2.通知具体人的手机号码列表
        atMap.put("atMobiles", "18683661017");
        Map<String, Object> reqMap = new HashMap<>();
        reqMap.put("msgtype", "text");
        //        JSONObject set =
        //                JSONUtil.createObj()
        //                        .set("title", SpringUtil.getActiveProfile() + "-" + title)
        //                        .set("text", content);

        reqMap.put("text", contentMap);
        reqMap.put("at", atMap);
        requestDTO.setContent(JSONUtil.toJsonStr(reqMap));

        try {
            String secret = requestDTO.getSecret();
            // 获取系统时间戳
            long timestamp = Instant.now().toEpochMilli();
            // 拼接
            String stringToSign = timestamp + "\n" + secret;
            // 使用HmacSHA256算法计算签名
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
            byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
            // 进行Base64 encode 得到最后的sign,可以拼接进url里
            String sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
            // 钉钉机器人地址(配置机器人的webhook)
            String dingUrl = requestDTO.getWebhook() + "&timestamp=" + timestamp + "&sign=" + sign;

            String result = HttpUtil.post(dingUrl, requestDTO.getContent());
            log.info("re={}", result);
        } catch (Exception e) {
            log.error("钉钉推送消息出现异常", e);
        }
    }

    @Data
    public static class DingTalkSendMsgRequestDTO {
        private String secret;
        private String webhook;
        private String content;
        private boolean isAtAll;
    }
}