|
|
@@ -1,17 +1,12 @@
|
|
|
package cn.snowheart.dingtalk.robot.starter.client;
|
|
|
|
|
|
-import cn.snowheart.dingtalk.robot.starter.entity.ActionCardButton;
|
|
|
-import cn.snowheart.dingtalk.robot.starter.entity.ActionCardMessage;
|
|
|
-import cn.snowheart.dingtalk.robot.starter.entity.BaseMessage;
|
|
|
-import cn.snowheart.dingtalk.robot.starter.entity.DingTalkResponse;
|
|
|
-import cn.snowheart.dingtalk.robot.starter.entity.FeedCardMessage;
|
|
|
-import cn.snowheart.dingtalk.robot.starter.entity.FeedCardMessageItem;
|
|
|
-import cn.snowheart.dingtalk.robot.starter.entity.LinkMessage;
|
|
|
-import cn.snowheart.dingtalk.robot.starter.entity.MarkdownMessage;
|
|
|
-import cn.snowheart.dingtalk.robot.starter.entity.TextMessage;
|
|
|
+import cn.snowheart.dingtalk.robot.starter.entity.*;
|
|
|
import cn.snowheart.dingtalk.robot.starter.exception.DingTalkException;
|
|
|
import cn.snowheart.dingtalk.robot.starter.type.HideAvatarType;
|
|
|
import cn.snowheart.dingtalk.robot.starter.type.ResponseCodeType;
|
|
|
+import org.apache.tomcat.util.codec.binary.Base64;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.beans.factory.annotation.Qualifier;
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
|
@@ -20,6 +15,11 @@ import org.springframework.http.HttpHeaders;
|
|
|
import org.springframework.http.MediaType;
|
|
|
import org.springframework.web.client.RestTemplate;
|
|
|
|
|
|
+import javax.crypto.Mac;
|
|
|
+import javax.crypto.spec.SecretKeySpec;
|
|
|
+import java.net.MalformedURLException;
|
|
|
+import java.net.URL;
|
|
|
+import java.net.URLEncoder;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
|
|
|
@@ -30,22 +30,81 @@ import java.util.Map;
|
|
|
* @version 1.0.0
|
|
|
*/
|
|
|
public class DingTalkRobotClient {
|
|
|
+ private final static Logger log = LoggerFactory.getLogger(DingTalkRobotClient.class);
|
|
|
|
|
|
@Autowired
|
|
|
@Qualifier("dingTalkRobotRestTemplate")
|
|
|
private RestTemplate restTemplate;
|
|
|
|
|
|
/**
|
|
|
- * 钉钉机器人WebHook地址的默认前缀,供AccessToken调用方式使用
|
|
|
+ * 钉钉机器人WebHook地址的默认前缀
|
|
|
*/
|
|
|
- @Value("${dingtalk.robot.prefix:https://oapi.dingtalk.com/robot/send?access_token=}")
|
|
|
- private String defaultUrlPrefix;
|
|
|
+ @Value("${dingtalk.robot.prefix:https://oapi.dingtalk.com/robot/send}")
|
|
|
+ private String urlPrefix;
|
|
|
+ /**
|
|
|
+ * 钉钉机器人WebHook地址的access_token
|
|
|
+ */
|
|
|
+ @Value("${dingtalk.robot.access_token}")
|
|
|
+ private String accessToken;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 钉钉机器人是否启用加签,默认false,启用加签需设置secret_token
|
|
|
+ */
|
|
|
+ @Value("${dingtalk.robot.secret.secret_enabled:false}")
|
|
|
+ private boolean secretEnable;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 钉钉机器人WebHook地址的secret_token,群机器人加签用
|
|
|
+ */
|
|
|
+ @Value("${dingtalk.robot.secret.secret_token:null}")
|
|
|
+ private String secretToken;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Gets default webhook.
|
|
|
+ * @return the default webhook
|
|
|
+ */
|
|
|
+ public String getDefaultWebhook() {
|
|
|
+ return getWebhook(accessToken);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Gets webhook.
|
|
|
+ * @param accessToken the access token
|
|
|
+ * @return the webhook
|
|
|
+ */
|
|
|
+ public String getWebhook(String accessToken) {
|
|
|
+ String url = urlPrefix + "?access_token=" + accessToken;
|
|
|
+ //若启用加签加上时间戳跟签名串
|
|
|
+ if (secretEnable) {
|
|
|
+ Long timestamp = System.currentTimeMillis();
|
|
|
+ url += "×tamp=" + timestamp
|
|
|
+ + "&sign=" + getSign(secretToken, timestamp);
|
|
|
+ }
|
|
|
+ log.debug(url);
|
|
|
+ return url;
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
- * 钉钉机器人的WebHook地址
|
|
|
+ * 计算签名
|
|
|
+ * 参考:https://ding-doc.dingtalk.com/doc#/serverapi2/qf2nxq/9e91d73c
|
|
|
+ * @param secret 密钥,机器人安全设置页面,加签一栏下面显示的SEC开头的字符
|
|
|
+ * @param @timestamp
|
|
|
+ * @return
|
|
|
*/
|
|
|
- @Value("${dingtalk.robot.webhook}")
|
|
|
- private String defaultWebhook;
|
|
|
+ static String getSign(String secret, Long timestamp) {
|
|
|
+ try {
|
|
|
+ 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"));
|
|
|
+ String sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
|
|
|
+ log.debug("【发送钉钉群消息】获取到签名sign = {}", sign);
|
|
|
+ return sign;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("【发送钉钉群消息】计算签名异常,errMsg = {}", e);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* 支持外部传入WebHook地址的方式发送消息
|
|
|
@@ -55,19 +114,39 @@ public class DingTalkRobotClient {
|
|
|
* @return
|
|
|
*/
|
|
|
public DingTalkResponse sendMessageByURL(String url, BaseMessage message) {
|
|
|
+ URL actualUrl;
|
|
|
+ try {
|
|
|
+ actualUrl = new URL(url);
|
|
|
+ } catch (MalformedURLException e) {
|
|
|
+ throw new RuntimeException("URL创建报错!");
|
|
|
+ }
|
|
|
+ return sendMessageByURL(actualUrl, message);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 支持外部传入WebHook地址的方式发送消息
|
|
|
+ *
|
|
|
+ * @param url
|
|
|
+ * @param message
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public DingTalkResponse sendMessageByURL(URL url, BaseMessage message) {
|
|
|
|
|
|
HttpHeaders headers = new HttpHeaders();
|
|
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
|
|
HttpEntity<Map> entity = new HttpEntity<>(message.toMessageMap(), headers);
|
|
|
+ try {
|
|
|
+ DingTalkResponse dingTalkResponse =
|
|
|
+ restTemplate.postForObject(url.toURI(), entity, DingTalkResponse.class);
|
|
|
|
|
|
- DingTalkResponse dingTalkResponse =
|
|
|
- restTemplate.postForObject(url, entity, DingTalkResponse.class);
|
|
|
-
|
|
|
- if (!ResponseCodeType.OK.getValue().equals(dingTalkResponse.getErrcode())) {
|
|
|
- throw new DingTalkException(dingTalkResponse.getErrcode(), dingTalkResponse.getErrmsg());
|
|
|
+ if (!ResponseCodeType.OK.getValue().equals(dingTalkResponse.getErrcode())) {
|
|
|
+ throw new DingTalkException(dingTalkResponse.getErrcode(), dingTalkResponse.getErrmsg());
|
|
|
+ }
|
|
|
+ return dingTalkResponse;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error(e.fillInStackTrace().toString());
|
|
|
+ return null;
|
|
|
}
|
|
|
-
|
|
|
- return dingTalkResponse;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -78,7 +157,7 @@ public class DingTalkRobotClient {
|
|
|
* @return
|
|
|
*/
|
|
|
public DingTalkResponse sendMessageByAccessToken(String accessToken, BaseMessage message) {
|
|
|
- return this.sendMessageByURL(defaultUrlPrefix + accessToken, message);
|
|
|
+ return this.sendMessageByURL(getWebhook(accessToken), message);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -88,7 +167,7 @@ public class DingTalkRobotClient {
|
|
|
* @return
|
|
|
*/
|
|
|
public DingTalkResponse sendMessage(BaseMessage message) {
|
|
|
- return this.sendMessageByURL(defaultWebhook, message);
|
|
|
+ return this.sendMessageByURL(getDefaultWebhook(), message);
|
|
|
}
|
|
|
|
|
|
/**
|