亚洲精品亚洲人成在线观看麻豆,在线欧美视频一区,亚洲国产精品一区二区动图,色综合久久丁香婷婷

              當(dāng)前位置:首頁 > IT技術(shù) > 微信平臺 > 正文

              Spring Boot 開發(fā)微信公眾號后臺
              2021-07-29 15:04:16

              Hello 各位小伙伴,松哥今天要和大家聊一個(gè)有意思的話題,就是使用 Spring Boot 開發(fā)微信公眾號后臺。

              很多小伙伴可能注意到松哥的個(gè)人網(wǎng)站(http://www.javaboy.org)前一陣子上線了一個(gè)公眾號內(nèi)回復(fù)口令解鎖網(wǎng)站文章的功能,還有之前就有的公眾號內(nèi)回復(fù)口令獲取超 2TB 免費(fèi)視頻教程的功能(免費(fèi)視頻教程),這兩個(gè)都是松哥基于 Spring Boot 來做的,最近松哥打算通過一個(gè)系列的文章,來向小伙伴們介紹下如何通過 Spring Boot 來開發(fā)公眾號后臺。

              1. 緣起

              今年 5 月份的時(shí)候,我想把我自己之前收集到的一些視頻教程分享給公眾號上的小伙伴,可是這些視頻教程大太了,無法一次分享,單次分享分享鏈接立馬就失效了,為了把這些視頻分享給大家,我把視頻拆分成了很多份,然后設(shè)置了不同的口令,小伙伴們在公眾號后臺通過回復(fù)口令就可以獲取到這些視頻,口令前前后后有 100 多個(gè),我一個(gè)一個(gè)手動(dòng)的在微信后臺進(jìn)行配置。這么搞工作量很大,前前后后大概花了三個(gè)晚上才把這些東西搞定。

              于是我就在想,該寫點(diǎn)代碼了。

              上個(gè)月買了服務(wù)器,也備案了,該有的都有了,于是就打算把這些資源用代碼實(shí)現(xiàn)下,因?yàn)榇髮W(xué)時(shí)候搞過公眾號開發(fā),倒也沒什么難度,于是說干就干。

              2. 實(shí)現(xiàn)思路

              其實(shí)松哥這個(gè)回復(fù)口令獲取視頻鏈接的實(shí)現(xiàn)原理很簡單,說白了,就是一個(gè)數(shù)據(jù)查詢操作而已,回復(fù)的口令是查詢關(guān)鍵字,回復(fù)的內(nèi)容則是查詢結(jié)果。這個(gè)原理很簡單。

              另一方面大家需要明白微信公眾號后臺開發(fā)消息發(fā)送的一個(gè)流程,大家看下面這張圖:

              ?

              這是大家在公眾號后臺回復(fù)關(guān)鍵字的情況。那么這個(gè)消息是怎么樣一個(gè)傳遞流程呢?我們來看看下面這張圖:

              Spring Boot 開發(fā)微信公眾號后臺_Spring Boot

              這張圖,我給大家稍微解釋下:

              1. 首先 javaboy4096 這個(gè)字符從公眾號上發(fā)送到了微信服務(wù)器
              2. 接下來微信服務(wù)器會把 javaboy4096 轉(zhuǎn)發(fā)到我自己的服務(wù)器上
              3. 我收到 javaboy4096 這個(gè)字符之后,就去數(shù)據(jù)庫中查詢,將查詢的結(jié)果,按照騰訊要求的 XML 格式進(jìn)行返回
              4. 微信服務(wù)器把從我的服務(wù)器收到的信息,再發(fā)回到微信上,于是小伙伴們就看到了返回結(jié)果了

              大致的流程就是這個(gè)樣子。

              接下來我們就來看一下實(shí)現(xiàn)細(xì)節(jié)。

              3. 公眾號后臺配置

              開發(fā)的第一步,是微信服務(wù)器要驗(yàn)證我們自己的服務(wù)器是否有效。

              首先我們登錄微信公眾平臺官網(wǎng)后,在公眾平臺官網(wǎng)的 開發(fā)-基本設(shè)置 頁面,勾選協(xié)議成為開發(fā)者,然后點(diǎn)擊“修改配置”按鈕,填寫:

              • 服務(wù)器地址(URL)
              • Token
              • EncodingAESKey

              Spring Boot 開發(fā)微信公眾號后臺_Spring Boot_02

              這里的 URL 配置好之后,我們需要針對這個(gè) URL 開發(fā)兩個(gè)接口,一個(gè)是 GET 請求的接口,這個(gè)接口用來做服務(wù)器有效性驗(yàn)證,另一個(gè)則是 POST 請求的接口,這個(gè)用來接收微信服務(wù)器發(fā)送來的消息。也就是說,微信服務(wù)器的消息都是通過 POST 請求發(fā)給我的。

              Token 可由開發(fā)者可以任意填寫,用作生成簽名(該 Token 會和接口 URL 中包含的 Token 進(jìn)行比對,從而驗(yàn)證安全性)。

              EncodingAESKey 由開發(fā)者手動(dòng)填寫或隨機(jī)生成,將用作消息體加解密密鑰。

              同時(shí),開發(fā)者可選擇消息加解密方式:明文模式、兼容模式和安全模式。明文模式就是我們自己的服務(wù)器收到微信服務(wù)器發(fā)來的消息是明文字符串,直接就可以讀取并且解析,安全模式則是我們收到微信服務(wù)器發(fā)來的消息是加密的消息,需要我們手動(dòng)解析后才能使用。

              4. 開發(fā)

              公眾號后臺配置完成后,接下來我們就可以寫代碼了。

              4.1 服務(wù)器有效性校驗(yàn)

              我們首先來創(chuàng)建一個(gè)普通的 Spring Boot 項(xiàng)目,創(chuàng)建時(shí)引入 spring-boot-starter-web 依賴,項(xiàng)目創(chuàng)建成功后,我們創(chuàng)建一個(gè) Controller ,添加如下接口:

              @GetMapping("/verify_wx_token")
              public void login(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
                  request.setCharacterEncoding("UTF-8");
                  String signature = request.getParameter("signature");
                  String timestamp = request.getParameter("timestamp");
                  String nonce = request.getParameter("nonce");
                  String echostr = request.getParameter("echostr");
                  PrintWriter out = null;
                  try {
                      out = response.getWriter();
                      if (CheckUtil.checkSignature(signature, timestamp, nonce)) {
                          out.write(echostr);
                      }
                  } catch (IOException e) {
                      e.printStackTrace();
                  } finally {
                      out.close();
                  }
              }
              

              關(guān)于這段代碼,我做如下解釋:

              1. 首先通過 request.getParameter 方法獲取到微信服務(wù)器發(fā)來的 signature、timestamp、nonce 以及 echostr 四個(gè)參數(shù),這四個(gè)參數(shù)中:signature 表示微信加密簽名,signature 結(jié)合了開發(fā)者填寫的 token 參數(shù)和請求中的timestamp參數(shù)、nonce參數(shù);timestamp 表示時(shí)間戳;nonce 表示隨機(jī)數(shù);echostr 則表示一個(gè)隨機(jī)字符串。
              2. 開發(fā)者通過檢驗(yàn) signature 對請求進(jìn)行校驗(yàn),如果確認(rèn)此次 GET 請求來自微信服務(wù)器,則原樣返回 echostr 參數(shù)內(nèi)容,則接入生效,成為開發(fā)者成功,否則接入失敗。
              3. 具體的校驗(yàn)就是松哥這里的 CheckUtil.checkSignature 方法,在這個(gè)方法中,首先將token、timestamp、nonce 三個(gè)參數(shù)進(jìn)行字典序排序,然后將三個(gè)參數(shù)字符串拼接成一個(gè)字符串進(jìn)行 sha1 加密,最后開發(fā)者獲得加密后的字符串可與 signature 對比,標(biāo)識該請求來源于微信。

              校驗(yàn)代碼如下:

              public class CheckUtil {
                  private static final String token = "123456";
                  public static boolean checkSignature(String signature, String timestamp, String nonce) {
                      String[] str = new String[]{token, timestamp, nonce};
                      //排序
                      Arrays.sort(str);
                      //拼接字符串
                      StringBuffer buffer = new StringBuffer();
                      for (int i = 0; i < str.length; i++) {
                          buffer.append(str[i]);
                      }
                      //進(jìn)行sha1加密
                      String temp = SHA1.encode(buffer.toString());
                      //與微信提供的signature進(jìn)行匹對
                      return signature.equals(temp);
                  }
              }
              public class SHA1 {
                  private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5',
                          '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
                  private static String getFormattedText(byte[] bytes) {
                      int len = bytes.length;
                      StringBuilder buf = new StringBuilder(len * 2);
                      for (int j = 0; j < len; j++) {
                          buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
                          buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
                      }
                      return buf.toString();
                  }
                  public static String encode(String str) {
                      if (str == null) {
                          return null;
                      }
                      try {
                          MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
                          messageDigest.update(str.getBytes());
                          return getFormattedText(messageDigest.digest());
                      } catch (Exception e) {
                          throw new RuntimeException(e);
                      }
                  }
              }
              

              OK,完成之后,我們的校驗(yàn)接口就算是開發(fā)完成了。接下來就可以開發(fā)消息接收接口了。

              4.2 消息接收接口

              接下來我們來開發(fā)消息接收接口,消息接收接口和上面的服務(wù)器校驗(yàn)接口地址是一樣的,都是我們一開始在公眾號后臺配置的地址。只不過消息接收接口是一個(gè) POST 請求。

              我在公眾號后臺配置的時(shí)候,消息加解密方式選擇了明文模式,這樣我在后臺收到的消息直接就可以處理了。微信服務(wù)器給我發(fā)來的普通文本消息格式如下:

              <xml>
                <ToUserName><![CDATA[toUser]]></ToUserName>
                <FromUserName><![CDATA[fromUser]]></FromUserName>
                <CreateTime>1348831860</CreateTime>
                <MsgType><![CDATA[text]]></MsgType>
                <Content><![CDATA[this is a test]]></Content>
                <MsgId>1234567890123456</MsgId>
              </xml>
              

              這些參數(shù)含義如下:

              參數(shù) 描述
              ToUserName 開發(fā)者微信號
              FromUserName 發(fā)送方帳號(一個(gè)OpenID)
              CreateTime 消息創(chuàng)建時(shí)間 (整型)
              MsgType 消息類型,文本為text
              Content 文本消息內(nèi)容
              MsgId 消息id,64位整型

              看到這里,大家心里大概就有數(shù)了,當(dāng)我們收到微信服務(wù)器發(fā)來的消息之后,我們就進(jìn)行 XML 解析,提取出來我們需要的信息,去做相關(guān)的查詢操作,再將查到的結(jié)果返回給微信服務(wù)器。

              這里我們先來個(gè)簡單的,我們將收到的消息解析并打印出來:

              @PostMapping("/verify_wx_token")
              public void handler(HttpServletRequest request, HttpServletResponse response) throws Exception {
                  request.setCharacterEncoding("UTF-8");
                  response.setCharacterEncoding("UTF-8");
                  PrintWriter out = response.getWriter();
                  Map<String, String> parseXml = MessageUtil.parseXml(request);
                  String msgType = parseXml.get("MsgType");
                  String content = parseXml.get("Content");
                  String fromusername = parseXml.get("FromUserName");
                  String tousername = parseXml.get("ToUserName");
                  System.out.println(msgType);
                  System.out.println(content);
                  System.out.println(fromusername);
                  System.out.println(tousername);
              }
              public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
                  Map<String, String> map = new HashMap<String, String>();
                  InputStream inputStream = request.getInputStream();
                  SAXReader reader = new SAXReader();
                  Document document = reader.read(inputStream);
                  Element root = document.getRootElement();
                  List<Element> elementList = root.elements();
                  for (Element e : elementList)
                      map.put(e.getName(), e.getText());
                  inputStream.close();
                  inputStream = null;
                  return map;
              }
              

              大家看到其實(shí)都是一些常規(guī)代碼,沒有什么難度。

              做完這些之后,我們將項(xiàng)目打成 jar 包在服務(wù)器上部署啟動(dòng)。啟動(dòng)成功之后,確認(rèn)微信的后臺配置也沒問題,我們就可以在公眾號上發(fā)一條消息了,這樣我們自己的服務(wù)端就會打印出來剛剛消息的信息。

              好了,篇幅限制,今天就和大家先聊這么多,后面再聊不同消息類型的解析和消息的返回問題。

              不知道小伙伴們看懂沒?有問題歡迎留言討論。

              參考資料:微信開放文檔

              ?Spring Boot 開發(fā)微信公眾號后臺_Spring Boot_03

              ?

              本文摘自 :https://blog.51cto.com/u

              開通會員,享受整站包年服務(wù)立即開通 >