零、前言
上一次做消息推送,是微信公众号的定时消息通知。
由于自己当时的水平不够,加上企鹅家的开发文档普遍不太友好,导致根本看不懂文档在写什么,不得不去看第三方博客来学习公众号的开发。
这次就不一样了,昨天刚看了一下,阿里的开发文档比鹅厂要清晰的多,而且在同一功能上,使用了多种语言作为示例代码,可以说很友好了。可能这就是阿里和鹅厂的区别吧...辣鸡文档和好文档的区别...
本着“授之以渔”的态度,写了这篇文章,作为官方文档的补充。
一、在群里添加机器人
在群设置的智能群助手中添加自定义机器人,它长这个样子:
比较关键的一步,是进行安全设置。
加密方式一共有三种,既可以选择一种也可以使用多种方式组合:
- 自定义关键词
- 加签
- IP地址
各种加密方式的介绍,详见官网:https://ding-doc.dingtalk.com/doc#/serverapi2/qf2nxq
为了让博客起到效果,我们选择相对安全、也比较难的加签方式。
选择加签之后,把密钥复制出来,然后就可以点确定了。
二、构建请求地址和内容
先看看官方文档怎么描述加签的:
第一步,把timestamp+"\n"+密钥当做签名字符串,使用HmacSHA256算法计算签名,然后进行Base64 encode,最后再把签名参数再进行urlEncode,得到最终的签名(需要使用UTF-8字符集)。
第二步,把 timestamp和第一步得到的签名值拼接到URL中。
官方的解释很高大上,其实原理很简单,就是把机器人密钥加密后,放在URL的参数中,所以我们需要分别获取时间戳和密钥,组合一下,加密一下,再拼接一下就好了,如图:
I have a Pen,
I have an Apple,
Oh~ Applepen~
官方给出了这样的示例代码:
import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; import java.net.URLEncoder; public class Test { public static void main(String[] args) throws Exception { Long timestamp = System.currentTimeMillis(); String secret = "this is secret"; 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"); System.out.println(sign); } }
然而,org.apache.commons.codec.binary.Base64不是Java的内置类,也就是说,示例代码并不能直接拿过来用:
查了一下,发现Java8中内置的java.util已经包含了Base64,因此用它替换掉原来的codec,无需再引入第三方包:
import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.util.Base64; import java.net.URLEncoder; public class ding { public static void main(String[] args) throws Exception { //获取时间戳 Long timestamp = System.currentTimeMillis(); //定义密钥 String secret = "this is secret"; //把时间戳和密钥拼接成字符串,中间加入一个换行符 String stringToSign = timestamp + "\n" + secret; //声明一个Mac对象,用来操作字符串 Mac mac = Mac.getInstance("HmacSHA256"); //初始化Mac对象,设置Mac对象操作的字符串是UTF-8类型,加密方式是SHA256 mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256")); //把字符串转化成字节形式 byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8")); //新建一个Base64编码对象 Base64.Encoder encoder = Base64.getEncoder(); //把上面的字符串进行Base64加密后再进行URL编码 String sign = URLEncoder.encode(new String(encoder.encodeToString(signData)),"UTF-8"); //分别输出时间戳和加密信息 System.out.println(timestamp); System.out.println(sign); } }
用最笨的方法,在终端执行一下看看:
成功输出了时间戳和验证信息。
我们测试上述代码的时候,可以手动拼接URL,直接发起请求:
(URL一共有三个参数:access_token、timestamp、sign,需要换成自己的,也就是上面终端输出的结果)
//替换参数后,在终端执行 curl 'https://oapi.dingtalk.com/robot/send?access_token=70c168d03e73728ef36abea63c3c10048cbd054913cfeb×tamp=1584607421017&sign=gJ3l4mhnlMuHxK1qFUx1kKUSdjuCNntsdG%2Bv%2BTCrLQM%3D' \ -H 'Content-Type: application/json' \ -d '{"msgtype": "text", "text": { "content": "我就是我, 是不一样的烟火" }, "sign": "gJ3l4mhnlMuHxK1qFUx1kKUSdjuCNntsdG%2Bv%2BTCrLQM%3D" }'
然后就出现了:
经过测试,代码正常运行,接下来就是部署到生产环境了。
三、部署代码
我们需要先找一下Spring如何发起HTTP请求。
以前,笔者只用过前台的HttpClient,对于后台的HTTP工具并不了解。
一开始尝试用Spring内置的RestTemplate,去网上查了它的用法,写了一堆代码,但怎么也不成功。由于从来没用过RestTemplate,也没耐心去看它的源码,于是放弃。
后来,只能老老实实的用apache的httpClient,查了一下用法,虽然有点麻烦,很多操作没法自动完成,但还算通俗易懂,而且它的包托管在Maven上,导入很方便。
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.9</version> </dependency>
httpClient的使用很灵活,这里使用的是POST方式,有一个参数,发起POST请求时,必须将字符集编码设置成UTF-8。
粗略步骤如图:
直接来一段稍微改一下就能用的代码:
public class DingService { //请求地址以及access_token String Webhook = "https://oapi.dingtalk.com/robot/send?access_token=YOUR TOKEN"; //密钥 String secret = "YOUR SECRET"; /* ** 生成时间戳和验证信息 */ public String encode() throws Exception { //获取时间戳 Long timestamp = System.currentTimeMillis(); //把时间戳和密钥拼接成字符串,中间加入一个换行符 String stringToSign = timestamp + "\n" + this.secret; //声明一个Mac对象,用来操作字符串 Mac mac = Mac.getInstance("HmacSHA256"); //初始化,设置Mac对象操作的字符串是UTF-8类型,加密方式是SHA256 mac.init(new SecretKeySpec(this.secret.getBytes("UTF-8"), "HmacSHA256")); //把字符串转化成字节形式 byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8")); //新建一个Base64编码对象 Base64.Encoder encoder = Base64.getEncoder(); //把上面的字符串进行Base64加密后再进行URL编码 String sign = URLEncoder.encode(new String(encoder.encodeToString(signData)),"UTF-8"); System.out.println(timestamp); System.out.println(sign); String result = "×tamp=" + timestamp + "&sign=" + sign; return result; }; /* param: message 要发送的信息 ** return: void 无返回值 ** 作用:把传入的message发送给钉钉机器人*/ public void dingRequest(String message){ CloseableHttpClient httpClient = HttpClientBuilder.create().build(); String url = null; try { url = this.Webhook + this.encode(); } catch (Exception e) { e.printStackTrace(); } HttpPost httpPost = new HttpPost(url); //设置http的请求头,发送json字符串,编码UTF-8 httpPost.setHeader("Content-Type", "application/json;charset=utf8"); //生成json对象传入字符 JSONObject result = new JSONObject(); JSONObject text = new JSONObject(); text.put("content", message); result.put("text", text); result.put("msgtype", "text"); String jsonString = JSON.toJSONString(result); StringEntity entity = new StringEntity(jsonString, "UTF-8"); //设置http请求的内容 httpPost.setEntity(entity); // 响应模型 CloseableHttpResponse response = null; try { // 由客户端执行(发送)Post请求 response = httpClient.execute(httpPost); // 从响应模型中获取响应实体 HttpEntity responseEntity = response.getEntity(); System.out.println("响应状态为:" + response.getStatusLine()); if (responseEntity != null) { System.out.println("响应内容长度为:" + responseEntity.getContentLength()); System.out.println("响应内容为:" + EntityUtils.toString(responseEntity)); } } catch (Exception e) { e.printStackTrace(); } finally { try { // 释放资源 if (httpClient != null) { httpClient.close(); } if (response != null) { response.close(); } } catch (Exception e) { e.printStackTrace(); } } } }
总结
其实消息推送的功能并不难,只是由于初次接触,需要查很多的文档,在这个过程中,锻炼了文本阅读能力和独立解决问题的能力。
参考资料
Java如何进行Base64的编码(Encode)与解码(Decode)
到此这篇关于SpringBoot实现钉钉机器人消息推送的示例代码的文章就介绍到这了,更多相关SpringBoot 钉钉机器人消息推送内容请搜索自学编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持自学编程网!
- 本文固定链接: https://zxbcw.cn/post/183129/
- 转载请注明:必须在正文中标注并保留原文链接
- QQ群: PHP高手阵营官方总群(344148542)
- QQ群: Yii2.0开发(304864863)