SpringBoot實(shí)現(xiàn)釘釘機(jī)器人消息推送的示例代碼
零、前言
上一次做消息推送,是微信公眾號的定時消息通知。
由于自己當(dāng)時的水平不夠,加上企鵝家的開發(fā)文檔普遍不太友好,導(dǎo)致根本看不懂文檔在寫什么,不得不去看第三方博客來學(xué)習(xí)公眾號的開發(fā)。
這次就不一樣了,昨天剛看了一下,阿里的開發(fā)文檔比鵝廠要清晰的多,而且在同一功能上,使用了多種語言作為示例代碼,可以說很友好了??赡苓@就是阿里和鵝廠的區(qū)別吧...辣雞文檔和好文檔的區(qū)別...
本著“授之以漁”的態(tài)度,寫了這篇文章,作為官方文檔的補(bǔ)充。
一、在群里添加機(jī)器人
在群設(shè)置的智能群助手中添加自定義機(jī)器人,它長這個樣子:
比較關(guān)鍵的一步,是進(jìn)行安全設(shè)置。
加密方式一共有三種,既可以選擇一種也可以使用多種方式組合:
- 自定義關(guān)鍵詞
- 加簽
- IP地址
各種加密方式的介紹,詳見官網(wǎng):https://ding-doc.dingtalk.com/doc#/serverapi2/qf2nxq
為了讓博客起到效果,我們選擇相對安全、也比較難的加簽方式。
選擇加簽之后,把密鑰復(fù)制出來,然后就可以點(diǎn)確定了。
二、構(gòu)建請求地址和內(nèi)容
先看看官方文檔怎么描述加簽的:
第一步,把timestamp+"\n"+密鑰當(dāng)做簽名字符串,使用HmacSHA256算法計(jì)算簽名,然后進(jìn)行Base64 encode,最后再把簽名參數(shù)再進(jìn)行urlEncode,得到最終的簽名(需要使用UTF-8字符集)。
第二步,把 timestamp和第一步得到的簽名值拼接到URL中。
官方的解釋很高大上,其實(shí)原理很簡單,就是把機(jī)器人密鑰加密后,放在URL的參數(shù)中,所以我們需要分別獲取時間戳和密鑰,組合一下,加密一下,再拼接一下就好了,如圖:
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的內(nèi)置類,也就是說,示例代碼并不能直接拿過來用:
查了一下,發(fā)現(xiàn)Java8中內(nèi)置的java.util已經(jīng)包含了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對象,設(shè)置Mac對象操作的字符串是UTF-8類型,加密方式是SHA256 mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256")); //把字符串轉(zhuǎn)化成字節(jié)形式 byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8")); //新建一個Base64編碼對象 Base64.Encoder encoder = Base64.getEncoder(); //把上面的字符串進(jìn)行Base64加密后再進(jìn)行URL編碼 String sign = URLEncoder.encode(new String(encoder.encodeToString(signData)),"UTF-8"); //分別輸出時間戳和加密信息 System.out.println(timestamp); System.out.println(sign); } }
用最笨的方法,在終端執(zhí)行一下看看:
成功輸出了時間戳和驗(yàn)證信息。
我們測試上述代碼的時候,可以手動拼接URL,直接發(fā)起請求:
(URL一共有三個參數(shù):access_token、timestamp、sign,需要換成自己的,也就是上面終端輸出的結(jié)果)
//替換參數(shù)后,在終端執(zhí)行 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" }'
然后就出現(xiàn)了:
經(jīng)過測試,代碼正常運(yùn)行,接下來就是部署到生產(chǎn)環(huán)境了。
三、部署代碼
我們需要先找一下Spring如何發(fā)起HTTP請求。
以前,筆者只用過前臺的HttpClient,對于后臺的HTTP工具并不了解。
一開始嘗試用Spring內(nèi)置的RestTemplate,去網(wǎng)上查了它的用法,寫了一堆代碼,但怎么也不成功。由于從來沒用過RestTemplate,也沒耐心去看它的源碼,于是放棄。
后來,只能老老實(shí)實(shí)的用apache的httpClient,查了一下用法,雖然有點(diǎn)麻煩,很多操作沒法自動完成,但還算通俗易懂,而且它的包托管在Maven上,導(dǎo)入很方便。
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.9</version> </dependency>
httpClient的使用很靈活,這里使用的是POST方式,有一個參數(shù),發(fā)起POST請求時,必須將字符集編碼設(shè)置成UTF-8。
粗略步驟如圖:
直接來一段稍微改一下就能用的代碼:
public class DingService { //請求地址以及access_token String Webhook = "https://oapi.dingtalk.com/robot/send?access_token=YOUR TOKEN"; //密鑰 String secret = "YOUR SECRET"; /* ** 生成時間戳和驗(yàn)證信息 */ public String encode() throws Exception { //獲取時間戳 Long timestamp = System.currentTimeMillis(); //把時間戳和密鑰拼接成字符串,中間加入一個換行符 String stringToSign = timestamp + "\n" + this.secret; //聲明一個Mac對象,用來操作字符串 Mac mac = Mac.getInstance("HmacSHA256"); //初始化,設(shè)置Mac對象操作的字符串是UTF-8類型,加密方式是SHA256 mac.init(new SecretKeySpec(this.secret.getBytes("UTF-8"), "HmacSHA256")); //把字符串轉(zhuǎn)化成字節(jié)形式 byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8")); //新建一個Base64編碼對象 Base64.Encoder encoder = Base64.getEncoder(); //把上面的字符串進(jìn)行Base64加密后再進(jìn)行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 要發(fā)送的信息 ** return: void 無返回值 ** 作用:把傳入的message發(fā)送給釘釘機(jī)器人*/ 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); //設(shè)置http的請求頭,發(fā)送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"); //設(shè)置http請求的內(nèi)容 httpPost.setEntity(entity); // 響應(yīng)模型 CloseableHttpResponse response = null; try { // 由客戶端執(zhí)行(發(fā)送)Post請求 response = httpClient.execute(httpPost); // 從響應(yīng)模型中獲取響應(yīng)實(shí)體 HttpEntity responseEntity = response.getEntity(); System.out.println("響應(yīng)狀態(tài)為:" + response.getStatusLine()); if (responseEntity != null) { System.out.println("響應(yīng)內(nèi)容長度為:" + responseEntity.getContentLength()); System.out.println("響應(yīng)內(nèi)容為:" + 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(); } } } }
總結(jié)
其實(shí)消息推送的功能并不難,只是由于初次接觸,需要查很多的文檔,在這個過程中,鍛煉了文本閱讀能力和獨(dú)立解決問題的能力。
參考資料
Java如何進(jìn)行Base64的編碼(Encode)與解碼(Decode)
到此這篇關(guān)于SpringBoot實(shí)現(xiàn)釘釘機(jī)器人消息推送的示例代碼的文章就介紹到這了,更多相關(guān)SpringBoot 釘釘機(jī)器人消息推送內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot整合MQTT并實(shí)現(xiàn)異步線程調(diào)用的問題
- SpringBoot集成mqtt的多模塊項(xiàng)目配置詳解
- springboot 實(shí)現(xiàn)mqtt物聯(lián)網(wǎng)的示例代碼
- SpringBoot+MQTT+apollo實(shí)現(xiàn)訂閱發(fā)布功能的示例
- springboot集成mqtt的實(shí)踐開發(fā)
- SpringBoot+netty-socketio實(shí)現(xiàn)服務(wù)器端消息推送
- SpringBoot+WebSocket+Netty實(shí)現(xiàn)消息推送的示例代碼
- springboot整合mqtt實(shí)現(xiàn)消息訂閱和推送功能
相關(guān)文章
Java算法之?dāng)?shù)組冒泡排序代碼實(shí)例講解
這篇文章主要介紹了Java算法之?dāng)?shù)組冒泡排序代碼實(shí)例講解,文中用代碼舉例講解的很清晰,有感興趣的同學(xué)可以研究下2021-03-03Java中List、Set、Map的區(qū)別和實(shí)現(xiàn)方式示例代碼
這篇文章主要介紹了Java中List、Set、Map的區(qū)別和實(shí)現(xiàn)方式示例代碼,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-06-06Java使用Spring Batch處理大規(guī)模數(shù)據(jù)的實(shí)踐分享
在處理大規(guī)模數(shù)據(jù)的場景中,批處理是一個非常常見且必要的操作,Java中的Spring Batch是一個強(qiáng)大的框架,能夠幫助我們高效地執(zhí)行復(fù)雜的批處理任務(wù),本文將帶大家了解如何使用Spring Batch處理大規(guī)模數(shù)據(jù),并通過代碼示例展示如何實(shí)現(xiàn)高效的批處理,需要的朋友可以參考下2024-10-10SpringBoot Nacos實(shí)現(xiàn)自動刷新
這篇文章主要介紹了SpringBoot Nacos實(shí)現(xiàn)自動刷新,Nacos(Dynamic Naming and Configuration Service)是阿里巴巴開源的一個動態(tài)服務(wù)發(fā)現(xiàn)、配置管理和服務(wù)管理平臺2023-01-01