浏览代码

modify method logic, see more ==>

spring-boot-dingtalk-robot-starter:
- 增加了新的贡献者Alex Hu
- 引入spring-boot-configuration-processor,完善对application.yml文件中配置项的提示
- 修改配置参数的格式,由access_token改为access-token
- 完善getWebhook方法
- 对sendMessageByURL()方法里面可能遇到的空指针异常做了处理

dingtalk-robot-demo:
- 增加了对getWebhook()的测试方法
- 更新依赖版本
Wanxiang Liu 5 年之前
父节点
当前提交
a53828e85a

+ 2 - 2
dingtalk-robot-demo/pom.xml

@@ -6,14 +6,14 @@
 
     <groupId>cn.snowheart</groupId>
     <artifactId>dingtalk-robot-demo</artifactId>
-    <version>1.0.2.RELEASE</version>
+    <version>1.0.3.RELEASE</version>
     <packaging>jar</packaging>
 
     <dependencies>
         <dependency>
             <groupId>cn.snowheart</groupId>
             <artifactId>spring-boot-dingtalk-robot-starter</artifactId>
-            <version>1.0.2.RELEASE</version>
+            <version>1.0.3.RELEASE</version>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>

+ 3 - 3
dingtalk-robot-demo/src/main/resources/application.yaml

@@ -1,7 +1,7 @@
 dingtalk:
   robot:
     prefix: https://oapi.dingtalk.com/robot/send
-    access_token: change-to-your-access-token
+    access-token: change-to-your-access-token
     secret:
-      secret_enabled: false
-      secret_token: change-to-your-secret-token
+      secret-enabled: false
+      secret-token: change-to-your-secret-token

+ 36 - 0
dingtalk-robot-demo/src/test/java/cn/snowheart/dingtalk/robot/demo/DemoApplicationTests.java

@@ -238,6 +238,42 @@ public class DemoApplicationTests {
         Thread.sleep(3000);
     }
 
+    /**
+     * 通过调用getWebhook方法来做外部的配置项传入,之后再进行消息发送
+     */
+    @Test
+    public void testGetWebhookAndSendMessage() throws InterruptedException {
+        DingTalkResponse response;
+
+        TextMessage message = new TextMessage("HelloWorld!");
+
+        String nonSignAccessToken = "change-to-your-access-token";
+        String signAccessToken = "change-to-your-access-token";
+        String signSecretToken = "change-to-your-secret-token";
+
+        String actualUrl;
+
+        actualUrl = client.getWebhook(nonSignAccessToken);
+        response = client.sendMessageByURL(actualUrl, message);
+        Assert.assertEquals(response.getErrcode().longValue(), 0L);
+        Thread.sleep(3000);
+
+        actualUrl = client.getWebhook(nonSignAccessToken, null, false);
+        response = client.sendMessageByURL(actualUrl, message);
+        Assert.assertEquals(response.getErrcode().longValue(), 0L);
+        Thread.sleep(3000);
+
+        actualUrl = client.getWebhook(signAccessToken, signSecretToken);
+        response = client.sendMessageByURL(actualUrl, message);
+        Assert.assertEquals(response.getErrcode().longValue(), 0L);
+        Thread.sleep(3000);
+
+        actualUrl = client.getWebhook(signAccessToken, signSecretToken, true);
+        response = client.sendMessageByURL(actualUrl, message);
+        Assert.assertEquals(response.getErrcode().longValue(), 0L);
+        Thread.sleep(3000);
+    }
+
     private static final String markDownDemoText = "标题\n" +
             "# 一级标题\n" +
             "## 二级标题\n" +

+ 15 - 2
spring-boot-dingtalk-robot-starter/pom.xml

@@ -6,7 +6,7 @@
 
     <groupId>cn.snowheart</groupId>
     <artifactId>spring-boot-dingtalk-robot-starter</artifactId>
-    <version>1.0.2.RELEASE</version>
+    <version>1.0.3.RELEASE</version>
     <packaging>jar</packaging>
 
     <name>dingtalk-robot</name>
@@ -17,13 +17,21 @@
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
         <java.version>1.8</java.version>
+        <spring-boot.version>2.2.5.RELEASE</spring-boot.version>
     </properties>
 
     <dependencies>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
-            <version>2.2.5.RELEASE</version>
+            <version>${spring-boot.version}</version>
+            <optional>true</optional>
+        </dependency>
+        <!-- SpringBoot configuration prompt. -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <version>${spring-boot.version}</version>
             <optional>true</optional>
         </dependency>
     </dependencies>
@@ -138,6 +146,11 @@
             <email>sxjwzxlwx@yeah.net</email>
             <organization>snowheart</organization>
         </developer>
+        <developer>
+            <name>Alex Hu</name>
+            <email>pa769@qq.com</email>
+            <organization>dimaidt</organization>
+        </developer>
     </developers>
 
 

+ 66 - 30
spring-boot-dingtalk-robot-starter/src/main/java/cn/snowheart/dingtalk/robot/starter/client/DingTalkRobotClient.java

@@ -17,8 +17,8 @@ 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.URI;
+import java.net.URISyntaxException;
 import java.net.URLEncoder;
 import java.util.List;
 import java.util.Map;
@@ -27,6 +27,7 @@ import java.util.Map;
  * 钉钉机器人客户端
  *
  * @author Wanxiang Liu
+ * @author Alex Hu
  * @version 1.0.0
  */
 public class DingTalkRobotClient {
@@ -44,54 +45,51 @@ public class DingTalkRobotClient {
     /**
      * 钉钉机器人WebHook地址的access_token
      */
-    @Value("${dingtalk.robot.access_token}")
+    @Value("${dingtalk.robot.access-token}")
     private String accessToken;
 
     /**
      * 钉钉机器人是否启用加签,默认false,启用加签需设置secret_token
      */
-    @Value("${dingtalk.robot.secret.secret_enabled:false}")
+    @Value("${dingtalk.robot.secret.secret-enabled:false}")
     private boolean secretEnable;
 
     /**
      * 钉钉机器人WebHook地址的secret_token,群机器人加签用
      */
-    @Value("${dingtalk.robot.secret.secret_token:null}")
+    @Value("${dingtalk.robot.secret.secret-token:null}")
     private String secretToken;
 
     /**
      * Gets default webhook.
+     *
      * @return the default webhook
      */
     public String getDefaultWebhook() {
-        return getWebhook(accessToken);
+        return getWebhook(accessToken, secretToken, secretEnable);
     }
 
     /**
      * Gets webhook.
+     * 隐含条件,加签功能关闭
+     * 传入accessToken,获取完整的WebHook URL。
+     *
      * @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 += "&timestamp=" + timestamp
-                    + "&sign=" + getSign(secretToken, timestamp);
-        }
-        log.debug(url);
-        return url;
+        return getWebhook(accessToken,null,false);
     }
 
     /**
      * 计算签名
      * 参考:https://ding-doc.dingtalk.com/doc#/serverapi2/qf2nxq/9e91d73c
+     *
      * @param secret    密钥,机器人安全设置页面,加签一栏下面显示的SEC开头的字符
-     * @param @timestamp
-     * @return
+     * @param timestamp 当前时间戳,毫秒级单位
+     * @return 根据时间戳计算后的签名信息
      */
-    static String getSign(String secret, Long timestamp) {
+    private static String getSign(String secret, Long timestamp) {
         try {
             String stringToSign = timestamp + "\n" + secret;
             Mac mac = Mac.getInstance("HmacSHA256");
@@ -114,10 +112,10 @@ public class DingTalkRobotClient {
      * @return
      */
     public DingTalkResponse sendMessageByURL(String url, BaseMessage message) {
-        URL actualUrl;
+        URI actualUrl;
         try {
-            actualUrl = new URL(url);
-        } catch (MalformedURLException e) {
+            actualUrl = new URI(url);
+        } catch (URISyntaxException e) {
             throw new RuntimeException("URL创建报错!");
         }
         return sendMessageByURL(actualUrl, message);
@@ -130,23 +128,29 @@ public class DingTalkRobotClient {
      * @param message
      * @return
      */
-    public DingTalkResponse sendMessageByURL(URL url, BaseMessage message) {
+    public DingTalkResponse sendMessageByURL(URI 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;
 
-            if (!ResponseCodeType.OK.getValue().equals(dingTalkResponse.getErrcode())) {
-                throw new DingTalkException(dingTalkResponse.getErrcode(), dingTalkResponse.getErrmsg());
-            }
-            return dingTalkResponse;
+        try {
+            dingTalkResponse =
+                    restTemplate.postForObject(url, entity, DingTalkResponse.class);
         } catch (Exception e) {
             log.error(e.fillInStackTrace().toString());
-            return null;
+            throw new DingTalkException(ResponseCodeType.UNKNOWN.getValue(), e.fillInStackTrace().toString());
+        }
+
+        // 对DingTalkResponse为空情况做异常封装
+        if (dingTalkResponse == null) {
+            throw new DingTalkException(ResponseCodeType.UNKNOWN.getValue(), "请求钉钉报错!");
+        }
+        if (!ResponseCodeType.OK.getValue().equals(dingTalkResponse.getErrcode())) {
+            throw new DingTalkException(dingTalkResponse.getErrcode(), dingTalkResponse.getErrmsg());
         }
+        return dingTalkResponse;
     }
 
     /**
@@ -369,4 +373,36 @@ public class DingTalkRobotClient {
     public DingTalkResponse sendFeedCardMessage(List<FeedCardMessageItem> feedCardItems) {
         return this.sendMessage(new FeedCardMessage(feedCardItems));
     }
+
+    /**
+     * Gets webhook.
+     * access_token、secret_token、secretEnable参数均由外部传入
+     *
+     * @param accessToken the access token
+     * @return the webhook
+     */
+    public String getWebhook(String accessToken, String secretToken, boolean secretEnable) {
+        String url = urlPrefix + "?access_token=" + accessToken;
+        //若启用加签加上时间戳跟签名串
+        if (secretEnable) {
+            Long timestamp = System.currentTimeMillis();
+            url += "&timestamp=" + timestamp
+                    + "&sign=" + getSign(secretToken, timestamp);
+        }
+        log.debug("The url contains sign is {}", url);
+        return url;
+    }
+
+    /**
+     * Gets webhook.
+     * 隐含条件,加签功能开启
+     * 传入accessToken和secretToken,获取完整的WebHook URL。
+     *
+     * @param accessToken
+     * @param secretToken
+     * @return
+     */
+    public String getWebhook(String accessToken, String secretToken) {
+        return getWebhook(accessToken, secretToken, true);
+    }
 }

+ 5 - 1
spring-boot-dingtalk-robot-starter/src/main/java/cn/snowheart/dingtalk/robot/starter/type/ResponseCodeType.java

@@ -11,7 +11,11 @@ public enum ResponseCodeType {
     /**
      * 消息发送成功
      */
-    OK(0);
+    OK(0),
+    /**
+     * 自定义相应码,非钉钉返回码值
+     */
+    UNKNOWN(9999);
 
     ResponseCodeType(Integer value) {
         this.value = value;

+ 28 - 1
spring-boot-dingtalk-robot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json

@@ -3,7 +3,34 @@
     {
       "name": "dingtalk.robot.webhook",
       "type": "java.lang.String",
-      "description": "DingTalk's WebHook-URL, include token."
+      "description": "DingTalk's WebHook-URL, include token.",
+      "deprecation": {
+        "reason": "The config property is deprecated. Use other supported clients instead."
+      }
+    },
+    {
+      "name": "dingtalk.robot.prefix",
+      "type": "java.lang.String",
+      "description": "DingTalk's WebHook url prefix, not include any parameters.",
+      "defaultValue": "https://oapi.dingtalk.com/robot/send"
+    },
+    {
+      "name": "dingtalk.robot.access-token",
+      "type": "java.lang.String",
+      "description": "DingTalk robot access_token parameter.",
+      "defaultValue": null
+    },
+    {
+      "name": "dingtalk.robot.secret.secret-enabled",
+      "type": "java.lang.Boolean",
+      "description": "Whether the robot sign parameter configuration is enabled.",
+      "defaultValue": false
+    },
+    {
+      "name": "dingtalk.robot.secret.secret-token",
+      "type": "java.lang.String",
+      "description": "DingTalk robot secret_token parameter, start with SEC.",
+      "defaultValue": null
     }
   ]
 }

+ 5 - 2
spring-boot-dingtalk-robot-starter/src/main/resources/application.yaml.template

@@ -1,4 +1,7 @@
 dingtalk:
   robot:
-    prefix: https://oapi.dingtalk.com/robot/send?access_token=
-    webhook: https://oapi.dingtalk.com/robot/send?access_token=7eb0673858d5b8636cc4189a708517478d3444f25fe887aef73c7bf99756127f
+    prefix: https://oapi.dingtalk.com/robot/send
+    access-token: change-to-your-access-token
+    secret:
+      secret-enabled: false
+      secret-token: change-to-your-secret-token