|
@@ -0,0 +1,199 @@
|
|
|
+package com.backendsys.modules.log.utils;
|
|
|
+
|
|
|
+import cn.hutool.http.HttpUtil;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.google.common.collect.Lists;
|
|
|
+import com.google.common.collect.Maps;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.codec.binary.Base64;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.core.env.Environment;
|
|
|
+import org.springframework.core.env.StandardEnvironment;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+
|
|
|
+import javax.crypto.Mac;
|
|
|
+import javax.crypto.spec.SecretKeySpec;
|
|
|
+import java.net.URLEncoder;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * 钉钉群机器人
|
|
|
+ * https://open.dingtalk.com/document/orgapp/robot-application-overview
|
|
|
+ * https://blog.csdn.net/weixin_44996457/article/details/128565224
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Component
|
|
|
+public class DingTalkPushUtil {
|
|
|
+
|
|
|
+ @Value("${ding-talk.enable}")
|
|
|
+ private Boolean isEnable;
|
|
|
+ @Value("${ding-talk.secret}")
|
|
|
+ private String secret;
|
|
|
+ @Value("${ding-talk.webhook}")
|
|
|
+ private String webhook;
|
|
|
+
|
|
|
+// private static final String secret = "SECf936313d718270626986fea3f1a6bfe2640f3cb653f45aa12ad68e7ddfd8c945";
|
|
|
+// private static final String webhook = "https://oapi.dingtalk.com/robot/send?access_token=6c677738c71a91ad096499784aa6bd0bb19ed99c2be99d31552ae3bb8fa7d5d5";
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 文本消息
|
|
|
+ */
|
|
|
+ public void testSendTextMsg() {
|
|
|
+ try {
|
|
|
+ sendTextMsg("我就是我, 是不一样的烟火", Lists.newArrayList(), Lists.newLinkedList(), false);
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.out.println("钉钉群消息发送异常,异常原因:");
|
|
|
+ System.out.println(e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * link类型
|
|
|
+ */
|
|
|
+ public void testSendLinkMsg() {
|
|
|
+ try {
|
|
|
+ sendLinkMsg("时代的火车向前开",
|
|
|
+ "这个即将发布的新版本,创始人xx称它为红树林。而在此之前,每当面临重大升级,产品经理们都会取一个应景的代号,这一次,为什么是红树林",
|
|
|
+ "https://www.dingtalk.com/s?__biz=MzA4NjMwMTA2Ng==&mid=2650316842&idx=1&sn=60da3ea2b29f1dcc43a7c8e4a7c97a16&scene=2&srcid=09189AnRJEdIiWVaKltFzNTw&from=timeline&isappinstalled=0&key=&ascene=2&uin=&devicetype=android-23&version=26031933&nettype=WIFI",
|
|
|
+ "");
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.out.println("钉钉群消息发送异常,异常原因:");
|
|
|
+ System.out.println(e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 群里面发送消息
|
|
|
+ *
|
|
|
+ * @param content 消息内容
|
|
|
+ * @param isAtAll 是否@所有人
|
|
|
+ * @param mobileList 被@人的手机号
|
|
|
+ * @param userIdList 被@人的用户userid
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public void sendTextMsg(String content, List<String> mobileList, List<String> userIdList, boolean isAtAll) throws Exception {
|
|
|
+ if (!isEnable) return;
|
|
|
+ String dingUrl = getDingUrl();
|
|
|
+ // 组装请求内容
|
|
|
+ String reqStr = buildReqTextStr(content, isAtAll, mobileList, userIdList);
|
|
|
+ // 推送消息(http请求)
|
|
|
+ String result = HttpUtil.post(dingUrl, reqStr);
|
|
|
+ handleErrorCode(result);
|
|
|
+ System.out.println();
|
|
|
+ System.out.println("钉钉请求发送成功,返回结果:");
|
|
|
+ System.out.println(result);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 群里面发送消息
|
|
|
+ *
|
|
|
+ * @param title 消息标题
|
|
|
+ * @param messageUrl 点击消息跳转的URL
|
|
|
+ * @param picUrl 图片URL
|
|
|
+ * @param text 消息内容
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public void sendLinkMsg(String title, String text, String messageUrl, String picUrl) throws Exception {
|
|
|
+ if (!isEnable) return;
|
|
|
+ String dingUrl = getDingUrl();
|
|
|
+ // 组装请求内容
|
|
|
+ String reqStr = buildReqLinkStr(title, text, messageUrl, picUrl);
|
|
|
+ // 推送消息(http请求)
|
|
|
+ String result = HttpUtil.post(dingUrl, reqStr);
|
|
|
+ handleErrorCode(result);
|
|
|
+ System.out.println("钉钉请求发送成功,返回结果:");
|
|
|
+ System.out.println(result);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 组装请求报文-link类型
|
|
|
+ *
|
|
|
+ * @param title 消息标题
|
|
|
+ * @param text 消息内容
|
|
|
+ * @param messageUrl 点击消息跳转的URL
|
|
|
+ * @param picUrl 图片URL
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String buildReqLinkStr(String title, String text, String messageUrl, String picUrl) {
|
|
|
+ Map<String, String> linkMap = Maps.newHashMap();
|
|
|
+
|
|
|
+ linkMap.put("text", text);
|
|
|
+ linkMap.put("title", title);
|
|
|
+ linkMap.put("picUrl", picUrl);
|
|
|
+ linkMap.put("messageUrl", messageUrl);
|
|
|
+
|
|
|
+ Map<String, Object> reqMap = Maps.newHashMap();
|
|
|
+ reqMap.put("msgtype", "link");
|
|
|
+ reqMap.put("link", linkMap);
|
|
|
+
|
|
|
+ return JSONObject.toJSONString(reqMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取请求url
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String getDingUrl() throws Exception {
|
|
|
+ // 获取系统时间戳
|
|
|
+ Long timestamp = System.currentTimeMillis();
|
|
|
+ // 拼接
|
|
|
+ String stringToSign = timestamp + "\n" + secret;
|
|
|
+ // 使用HmacSHA256算法计算签名
|
|
|
+ Mac mac = Mac.getInstance("HmacSHA256");
|
|
|
+ mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
|
|
|
+ byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
|
|
|
+ // 进行Base64 encode 得到最后的sign,可以拼接进url里
|
|
|
+ String sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");//Base64.encodeBase64(signData)
|
|
|
+ // 钉钉机器人地址(配置机器人的webhook),为了让每次请求不同,避免钉钉拦截,加上时间戳
|
|
|
+ String dingUrl = webhook + "×tamp=" + timestamp + "&sign=" + sign;
|
|
|
+ return dingUrl;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 组装请求报文-text类型
|
|
|
+ *
|
|
|
+ * @param content 消息内容
|
|
|
+ * @param isAtAll 是否@所有人
|
|
|
+ * @param mobileList 被@人的手机号
|
|
|
+ * @param atUserIds 被@人的用户userid
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String buildReqTextStr(String content, boolean isAtAll, List<String> mobileList, List<String> atUserIds) {
|
|
|
+ Map<String, String> contentMap = Maps.newHashMap();
|
|
|
+ contentMap.put("content", content);
|
|
|
+
|
|
|
+ Map<String, Object> atMap = Maps.newHashMap();
|
|
|
+ atMap.put("isAtAll", isAtAll);
|
|
|
+ atMap.put("atMobiles", mobileList);
|
|
|
+ atMap.put("atUserIds", atUserIds);
|
|
|
+
|
|
|
+ Map<String, Object> reqMap = Maps.newHashMap();
|
|
|
+ reqMap.put("msgtype", "text");
|
|
|
+ reqMap.put("text", contentMap);
|
|
|
+ reqMap.put("at", atMap);
|
|
|
+
|
|
|
+ return JSONObject.toJSONString(reqMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * errcode处理
|
|
|
+ * @param resultStr
|
|
|
+ */
|
|
|
+ private void handleErrorCode(String resultStr) {
|
|
|
+ if (StringUtils.isEmpty(resultStr)) {
|
|
|
+ throw new RuntimeException("返回结果为空");
|
|
|
+ }
|
|
|
+ JSONObject jsonObject = JSONObject.parseObject(resultStr);
|
|
|
+ if (310000 == jsonObject.getLong("errcode")) {
|
|
|
+ throw new RuntimeException("keywords not in content");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|