微信開發學習總結(二)——微信開發入門

  上一篇《微信開發學習總結(一)——微信開發環境搭建》咱們已經完成了微信開發的準備工做,準備工做完成以後,就要開始步入正題了。html

1、微信公衆平臺的基本原理

  在開始作以前,先簡單介紹了微信公衆平臺的基本原理。java

  微信服務器就至關於一個轉發服務器,終端(手機、Pad等)發起請求至微信服務器,微信服務器而後將請求轉發給咱們的應用服務器。應用服務器處理完畢後,將響應數據回發給微信服務器,微信服務器再將具體響應信息回覆到微信App終端。android

  通訊協議爲:HTTPweb

  數據傳輸格式爲:XMLjson

  具體的流程以下圖所示:api

  

  來一張更加直觀的圖吧:數組

  

  咱們須要作的事情,就是對微信服務器轉發的HTTP請求作出響應。具體的請求內容,咱們按照特定的XML格式去解析,處理完畢後,也要按照特定的XML格式返回。安全

2、微信公衆號接入

  在微信公衆平臺開發者文檔上,關於公衆號接入這一節內容在接入指南上寫的比較詳細的,文檔中說接入公衆號須要3個步驟,分別是:服務器

  一、填寫服務器配置
  二、驗證服務器地址的有效性
  三、依據接口文檔實現業務邏輯微信

  其實,第3步已經不能算作公衆號接入的步驟,而是接入以後,開發人員能夠根據微信公衆號提供的接口所能作的一些開發。

  第1步中服務器配置包含服務器地址(URL)、Token和EncodingAESKey。

  服務器地址即公衆號後臺提供業務邏輯的入口地址,目前只支持80端口,以後包括接入驗證以及任何其它的操做的請求(例如消息的發送、菜單管理、素材管理等)都要從這個地址進入。接入驗證和其它請求的區別就是,接入驗證時是get請求,其它時候是post請求;

  Token可由開發者能夠任意填寫,用做生成簽名(該Token會和接口URL中包含的Token進行比對,從而驗證安全性);

  EncodingAESKey由開發者手動填寫或隨機生成,將用做消息體加解密密鑰。本例中所有以未加密的明文消息方式,不涉及此配置項。

  第2步,驗證服務器地址的有效性,當點擊「提交」按鈕後,微信服務器將發送一個http的get請求到剛剛填寫的服務器地址,而且攜帶四個參數:

  

  接到請求後,咱們須要作以下三步,若確認這次GET請求來自微信服務器,原樣返回echostr參數內容,則接入生效,不然接入失敗。

  1. 將token、timestamp、nonce三個參數進行字典序排序
  2. 將三個參數字符串拼接成一個字符串進行sha1加密
  3. 開發者得到加密後的字符串可與signature對比,標識該請求來源於微信

  下面咱們用Java代碼來演示一下這個驗證過程

  使用IDE(Eclipse或者IntelliJ IDEA)建立一個JavaWeb項目,這裏我使用的是IntelliJ IDEA,項目目錄結構以下圖所示:

  

  編寫一個servlevt,在其中的doGet方法中定義校驗方法,具體代碼以下:

  1 package me.gacl.wx.web.servlet;
  2 
  3 import javax.servlet.ServletException;
  4 import javax.servlet.annotation.WebServlet;
  5 import javax.servlet.http.HttpServlet;
  6 import javax.servlet.http.HttpServletRequest;
  7 import javax.servlet.http.HttpServletResponse;
  8 import java.io.IOException;
  9 import java.security.MessageDigest;
 10 import java.security.NoSuchAlgorithmException;
 11 import java.util.Arrays;
 12 
 13 /**
 14  * Created by xdp on 2016/1/25.
 15  * 使用@WebServlet註解配置WxServlet,urlPatterns屬性指明瞭WxServlet的訪問路徑
 16  */
 17 @WebServlet(urlPatterns="/WxServlet")
 18 public class WxServlet extends HttpServlet {
 19 
 20     /**
 21      * Token可由開發者能夠任意填寫,用做生成簽名(該Token會和接口URL中包含的Token進行比對,從而驗證安全性)
 22      * 好比這裏我將Token設置爲gacl
 23      */
 24     private final String TOKEN = "gacl";
 25 
 26     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 27 
 28     }
 29 
 30     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 31         System.out.println("開始校驗簽名");
 32         /**
 33          * 接收微信服務器發送請求時傳遞過來的4個參數
 34          */
 35         String signature = request.getParameter("signature");//微信加密簽名signature結合了開發者填寫的token參數和請求中的timestamp參數、nonce參數。
 36         String timestamp = request.getParameter("timestamp");//時間戳
 37         String nonce = request.getParameter("nonce");//隨機數
 38         String echostr = request.getParameter("echostr");//隨機字符串
 39         //排序
 40         String sortString = sort(TOKEN, timestamp, nonce);
 41         //加密
 42         String mySignature = sha1(sortString);
 43         //校驗簽名
 44         if (mySignature != null && mySignature != "" && mySignature.equals(signature)) {
 45             System.out.println("簽名校驗經過。");
 46             //若是檢驗成功輸出echostr,微信服務器接收到此輸出,纔會確認檢驗完成。
 47             //response.getWriter().println(echostr);
 48             response.getWriter().write(echostr);
 49         } else {
 50             System.out.println("簽名校驗失敗.");
 51         }
 52 
 53     }
 54 
 55     /**
 56      * 排序方法
 57      *
 58      * @param token
 59      * @param timestamp
 60      * @param nonce
 61      * @return
 62      */
 63     public String sort(String token, String timestamp, String nonce) {
 64         String[] strArray = {token, timestamp, nonce};
 65         Arrays.sort(strArray);
 66         StringBuilder sb = new StringBuilder();
 67         for (String str : strArray) {
 68             sb.append(str);
 69         }
 70 
 71         return sb.toString();
 72     }
 73 
 74     /**
 75      * 將字符串進行sha1加密
 76      *
 77      * @param str 須要加密的字符串
 78      * @return 加密後的內容
 79      */
 80     public String sha1(String str) {
 81         try {
 82             MessageDigest digest = MessageDigest.getInstance("SHA-1");
 83             digest.update(str.getBytes());
 84             byte messageDigest[] = digest.digest();
 85             // Create Hex String
 86             StringBuffer hexString = new StringBuffer();
 87             // 字節數組轉換爲 十六進制 數
 88             for (int i = 0; i < messageDigest.length; i++) {
 89                 String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
 90                 if (shaHex.length() < 2) {
 91                     hexString.append(0);
 92                 }
 93                 hexString.append(shaHex);
 94             }
 95             return hexString.toString();
 96 
 97         } catch (NoSuchAlgorithmException e) {
 98             e.printStackTrace();
 99         }
100         return "";
101     }
102 }

  我這裏用的Servlet3.0,使用Servlet3.0的好處就是能夠直接使用@WebServlet註解映射Servlet的訪問路徑,再也不須要在web.xml文件中進行配置.

  將WxStudy項目部署到Tomcat服務器中運行,直接啓動項目,而後用ngrok將本地8080端口映射到外網(如何使用ngrok請參考博客《微信開發學習總結(一)——微信開發環境搭建》)。以下圖所示:

  

  測試是否能夠經過http://xdp.ngrok.natapp.cn地址正常訪問,測試結果以下:

  

  能夠看到,咱們的項目已經能夠被外網正常訪問到了。

  進入微信測試公衆號管理界面,在接口配置信息中填入映射的外網地址和token,以下圖所示:

 

  點擊提交按鈕,頁面會提示配置成功,

  

  IDE的控制檯中輸出了校驗經過的信息,以下圖所示:

  

  到此,咱們的公衆號應用已經可以和微信服務器正常通訊了,也就是說咱們的公衆號已經接入到微信公衆平臺了。

3、access_token管理

3.一、access_token介紹

  咱們的公衆號和微信服務器對接成功以後,接下來要作的就是根據咱們的業務需求調用微信公衆號提供的接口來實現相應的邏輯了。在使用微信公衆號接口中都須要一個access_token。

  關於access_token,在微信公衆平臺開發者文檔上的獲取接口調用憑據有比較詳細的介紹:access_token是公衆號的全局惟一票據,公衆號調用各接口時都需使用access_token,開發者須要妥善保存access_token的存儲至少要保留512個字符空間。access_token的有效期目前爲2個小時,需定時刷新,重複獲取將致使上次獲取的access_token失效。而且天天調用獲取access_token接口的上限是2000次。

  總結以上說明,access_token須要作到如下兩點:

  1.由於access_token有2個小時的時效性,要有一個機制保證最長2個小時從新獲取一次。

  2.由於接口調用上限天天2000次,因此不能調用太頻繁。

3.二、微信公衆平臺提供的獲取access_token的接口

  關於access_token的獲取方式,在微信公衆平臺開發者文檔上有說明,公衆號能夠調用一個叫"獲取access token"的接口來獲取access_token。

  獲取access token接口調用請求說明

    http請求方式: GET

    請求的URL地址:https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
    
  

  咱們能夠看到,調用過程當中須要傳遞appID和AppSecret,appID和AppSecret是在申請公衆號的時候自動分配給公衆號的,至關於公衆號的身份標示,使用微信公衆號的註冊賬號登陸到騰訊提供的微信公衆號管理後臺就能夠看到本身申請的公衆號的AppID和AppSecret,以下圖所示:

  

  這是我申請公衆號測試賬號時分配到的AppID和AppSecret。

3.三、獲取access_token方案以及具體實現

  這裏採用的方案是這樣的,定義一個默認啓動的servlet,在init方法中啓動一個Thread,這個進程中定義一個無限循環的方法,用來獲取access_token,當獲取成功後,此進程休眠7000秒(7000秒=1.944444444444444小時),不然休眠3秒鐘繼續獲取。流程圖以下:

  

  下面正式開始在工程中實現以上思路,由於返回的數據都是json格式,這裏會用到阿里的fastjson庫,爲構造請求和處理請求後的數據序列化和反序列化提供支持。

  1.定義一個AccessToken實體類

 1 package me.gacl.wx.entry;
 2 
 3 /**
 4  * AccessToken的數據模型
 5  * Created by xdp on 2016/1/25.
 6  */
 7 public class AccessToken {
 8 
 9     //獲取到的憑證
10     private String accessToken;
11     //憑證有效時間,單位:秒
12     private int expiresin;
13 
14     public String getAccessToken() {
15         return accessToken;
16     }
17 
18     public void setAccessToken(String accessToken) {
19         this.accessToken = accessToken;
20     }
21 
22     public int getExpiresin() {
23         return expiresin;
24     }
25 
26     public void setExpiresin(int expiresin) {
27         this.expiresin = expiresin;
28     }
29 }

 2.定義一個AccessTokenInfo類,用於存放獲取到的AccessToken,代碼以下:

 1 package me.gacl.wx.Common;
 2 
 3 import me.gacl.wx.entry.AccessToken;
 4 
 5 /**
 6  * Created by xdp on 2016/1/25.
 7  */
 8 public class AccessTokenInfo {
 9 
10     //注意是靜態的
11     public static AccessToken accessToken = null;
12 }

  3.編寫一個用於發起https請求的工具類NetWorkHelper,代碼以下:

 1 package me.gacl.wx.util;
 2 
 3 import javax.net.ssl.*;
 4 import java.io.BufferedReader;
 5 import java.io.InputStream;
 6 import java.io.InputStreamReader;
 7 import java.net.URL;
 8 import java.security.cert.CertificateException;
 9 import java.security.cert.X509Certificate;
10 
11 /**
12  * 訪問網絡用到的工具類
13  */
14 public class NetWorkHelper {
15 
16     /**
17      * 發起Https請求
18      * @param reqUrl 請求的URL地址
19      * @param requestMethod
20      * @return 響應後的字符串
21      */
22     public String getHttpsResponse(String reqUrl, String requestMethod) {
23         URL url;
24         InputStream is;
25         String resultData = "";
26         try {
27             url = new URL(reqUrl);
28             HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
29             TrustManager[] tm = {xtm};
30 
31             SSLContext ctx = SSLContext.getInstance("TLS");
32             ctx.init(null, tm, null);
33 
34             con.setSSLSocketFactory(ctx.getSocketFactory());
35             con.setHostnameVerifier(new HostnameVerifier() {
36                 @Override
37                 public boolean verify(String arg0, SSLSession arg1) {
38                     return true;
39                 }
40             });
41 
42 
43             con.setDoInput(true); //容許輸入流,即容許下載
44 
45             //在android中必須將此項設置爲false
46             con.setDoOutput(false); //容許輸出流,即容許上傳
47             con.setUseCaches(false); //不使用緩衝
48             if (null != requestMethod && !requestMethod.equals("")) {
49                 con.setRequestMethod(requestMethod); //使用指定的方式
50             } else {
51                 con.setRequestMethod("GET"); //使用get請求
52             }
53             is = con.getInputStream();   //獲取輸入流,此時才真正創建連接
54             InputStreamReader isr = new InputStreamReader(is);
55             BufferedReader bufferReader = new BufferedReader(isr);
56             String inputLine;
57             while ((inputLine = bufferReader.readLine()) != null) {
58                 resultData += inputLine + "\n";
59             }
60             System.out.println(resultData);
61 
62         } catch (Exception e) {
63             e.printStackTrace();
64         }
65         return resultData;
66     }
67 
68     X509TrustManager xtm = new X509TrustManager() {
69         @Override
70         public X509Certificate[] getAcceptedIssuers() {
71             return null;
72         }
73 
74         @Override
75         public void checkServerTrusted(X509Certificate[] arg0, String arg1)
76                 throws CertificateException {
77 
78         }
79 
80         @Override
81         public void checkClientTrusted(X509Certificate[] arg0, String arg1)
82                 throws CertificateException {
83 
84         }
85     };
86 }

  getHttpsResponse方法是請求一個https地址,參數requestMethod爲字符串「GET」或者「POST」,傳null或者「」默認爲get方式。

  4.定義一個默認啓動的servlet,在init方法中啓動一個新的線程去獲取accessToken

 1 package me.gacl.wx.web.servlet;
 2 
 3 import com.alibaba.fastjson.JSON;
 4 import com.alibaba.fastjson.JSONObject;
 5 import me.gacl.wx.Common.AccessTokenInfo;
 6 import me.gacl.wx.entry.AccessToken;
 7 import me.gacl.wx.util.NetWorkHelper;
 8 
 9 import javax.servlet.ServletException;
10 import javax.servlet.annotation.WebInitParam;
11 import javax.servlet.annotation.WebServlet;
12 import javax.servlet.http.HttpServlet;
13 
14 /**
15  * 用於獲取accessToken的Servlet
16  * Created by xdp on 2016/1/25.
17  */
18 @WebServlet(
19         name = "AccessTokenServlet",
20         urlPatterns = {"/AccessTokenServlet"},
21         loadOnStartup = 1,
22         initParams = {
23                 @WebInitParam(name = "appId", value = "wxbe4d433e857e8bb1"),
24                 @WebInitParam(name = "appSecret", value = "ccbc82d560876711027b3d43a6f2ebda")
25         })
26 public class AccessTokenServlet extends HttpServlet {
27 
28     @Override
29     public void init() throws ServletException {
30         System.out.println("啓動WebServlet");
31         super.init();
32 
33         final String appId = getInitParameter("appId");
34         final String appSecret = getInitParameter("appSecret");
35 
36         //開啓一個新的線程
37         new Thread(new Runnable() {
38             @Override
39             public void run() {
40                 while (true) {
41                     try {
42                         //獲取accessToken
43                         AccessTokenInfo.accessToken = getAccessToken(appId, appSecret);
44                         //獲取成功
45                         if (AccessTokenInfo.accessToken != null) {
46                             //獲取到access_token 休眠7000秒,大約2個小時左右
47                             Thread.sleep(7000 * 1000);
48                             //Thread.sleep(10 * 1000);//10秒鐘獲取一次
49                         } else {
50                             //獲取失敗
51                             Thread.sleep(1000 * 3); //獲取的access_token爲空 休眠3秒
52                         }
53                     } catch (Exception e) {
54                         System.out.println("發生異常:" + e.getMessage());
55                         e.printStackTrace();
56                         try {
57                             Thread.sleep(1000 * 10); //發生異常休眠1秒
58                         } catch (Exception e1) {
59 
60                         }
61                     }
62                 }
63 
64             }
65         }).start();
66     }
67 
68     /**
69      * 獲取access_token
70      *
71      * @return AccessToken
72      */
73     private AccessToken getAccessToken(String appId, String appSecret) {
74         NetWorkHelper netHelper = new NetWorkHelper();
75         /**
76          * 接口地址爲https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET,其中grant_type固定寫爲client_credential便可。
77          */
78         String Url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", appId, appSecret);
79         //此請求爲https的get請求,返回的數據格式爲{"access_token":"ACCESS_TOKEN","expires_in":7200}
80         String result = netHelper.getHttpsResponse(Url, "");
81         System.out.println("獲取到的access_token="+result);
82         //使用FastJson將Json字符串解析成Json對象
83         JSONObject json = JSON.parseObject(result);
84         AccessToken token = new AccessToken();
85         token.setAccessToken(json.getString("access_token"));
86         token.setExpiresin(json.getInteger("expires_in"));
87         return token;
88     }
89 }

  AccessTokenServlet採用註解的方式進行配置
  至此代碼實現完畢,將項目部署,看到控制檯輸出以下:

  

  爲了方便看效果,能夠把休眠時間設置短一點,好比10秒獲取一次,而後將access_token輸出。

  下面作一個測試jsp頁面,並把休眠時間設置爲10秒,這樣過10秒刷新頁面,就能夠看到變化

 1 <%-- Created by IntelliJ IDEA. --%>
 2 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 3 <%@ page import="me.gacl.wx.Common.AccessTokenInfo"%>
 4 <html>
 5   <head>
 6     <title></title>
 7   </head>
 8   <body>
 9     微信學習
10     <hr/>
11     access_token爲:<%=AccessTokenInfo.accessToken.getAccessToken()%>
12   </body>
13 </html>

  

  10秒鐘後刷新頁面,access_token變了,以下圖所示:

  

4、接收微信服務器發送的消息並作出響應

  通過上述的三步,咱們開發前的準備工做已經完成了,接下來要作的就是接收微信服務器發送的消息並作出響應

  從微信公衆平臺接口消息指南中能夠了解到,當用戶向公衆賬號發消息時,微信服務器會將消息經過POST方式提交給咱們在接口配置信息中填寫的URL,而咱們就須要在URL所指向的請求處理類WxServlet的doPost方法中接收消息、處理消息和響應消息。

4.1.編寫一個用於處理消息的工具類

  編寫處理消息的工具欄,工具類代碼以下:

  1 package me.gacl.wx.util;
  2 
  3 import org.dom4j.Document;
  4 import org.dom4j.Element;
  5 import org.dom4j.io.SAXReader;
  6 
  7 import javax.servlet.http.HttpServletRequest;
  8 import java.io.InputStream;
  9 import java.text.DateFormat;
 10 import java.text.SimpleDateFormat;
 11 import java.util.Date;
 12 import java.util.HashMap;
 13 import java.util.List;
 14 import java.util.Map;
 15 
 16 /**
 17  * 消息處理工具類
 18  * Created by xdp on 2016/1/26.
 19  */
 20 public class MessageHandlerUtil {
 21 
 22     /**
 23      * 解析微信發來的請求(XML)
 24      * @param request
 25      * @return map
 26      * @throws Exception
 27      */
 28     public static Map<String,String> parseXml(HttpServletRequest request) throws Exception {
 29         // 將解析結果存儲在HashMap中
 30         Map<String,String> map = new HashMap();
 31         // 從request中取得輸入流
 32         InputStream inputStream = request.getInputStream();
 33         System.out.println("獲取輸入流");
 34         // 讀取輸入流
 35         SAXReader reader = new SAXReader();
 36         Document document = reader.read(inputStream);
 37         // 獲得xml根元素
 38         Element root = document.getRootElement();
 39         // 獲得根元素的全部子節點
 40         List<Element> elementList = root.elements();
 41 
 42         // 遍歷全部子節點
 43         for (Element e : elementList) {
 44             System.out.println(e.getName() + "|" + e.getText());
 45             map.put(e.getName(), e.getText());
 46         }
 47 
 48         // 釋放資源
 49         inputStream.close();
 50         inputStream = null;
 51         return map;
 52     }
 53 
 54     // 根據消息類型 構造返回消息
 55     public static String buildXml(Map<String,String> map) {
 56         String result;
 57         String msgType = map.get("MsgType").toString();
 58         System.out.println("MsgType:" + msgType);
 59         if(msgType.toUpperCase().equals("TEXT")){
 60             result = buildTextMessage(map, "孤傲蒼狼在學習和總結微信開發了,構建一條文本消息:Hello World!");
 61         }else{
 62             String fromUserName = map.get("FromUserName");
 63             // 開發者微信號
 64             String toUserName = map.get("ToUserName");
 65             result = String
 66                     .format(
 67                             "<xml>" +
 68                                     "<ToUserName><![CDATA[%s]]></ToUserName>" +
 69                                     "<FromUserName><![CDATA[%s]]></FromUserName>" +
 70                                     "<CreateTime>%s</CreateTime>" +
 71                                     "<MsgType><![CDATA[text]]></MsgType>" +
 72                                     "<Content><![CDATA[%s]]></Content>" +
 73                                     "</xml>",
 74                             fromUserName, toUserName, getUtcTime(),
 75                             "請回復以下關鍵詞:\n文本\n圖片\n語音\n視頻\n音樂\n圖文");
 76         }
 77 
 78         return result;
 79     }
 80 
 81     /**
 82      * 構造文本消息
 83      *
 84      * @param map
 85      * @param content
 86      * @return
 87      */
 88     private static String buildTextMessage(Map<String,String> map, String content) {
 89         //發送方賬號
 90         String fromUserName = map.get("FromUserName");
 91         // 開發者微信號
 92         String toUserName = map.get("ToUserName");
 93         /**
 94          * 文本消息XML數據格式
 95          * <xml>
 96              <ToUserName><![CDATA[toUser]]></ToUserName>
 97              <FromUserName><![CDATA[fromUser]]></FromUserName>
 98              <CreateTime>1348831860</CreateTime>
 99              <MsgType><![CDATA[text]]></MsgType>
100              <Content><![CDATA[this is a test]]></Content>
101              <MsgId>1234567890123456</MsgId>
102          </xml>
103          */
104         return String.format(
105                 "<xml>" +
106                         "<ToUserName><![CDATA[%s]]></ToUserName>" +
107                         "<FromUserName><![CDATA[%s]]></FromUserName>" +
108                         "<CreateTime>%s</CreateTime>" +
109                         "<MsgType><![CDATA[text]]></MsgType>" +
110                         "<Content><![CDATA[%s]]></Content>" + "</xml>",
111                 fromUserName, toUserName, getUtcTime(), content);
112     }
113 
114     private static String getUtcTime() {
115         Date dt = new Date();// 若是不須要格式,可直接用dt,dt就是當前系統時間
116         DateFormat df = new SimpleDateFormat("yyyyMMddhhmm");// 設置顯示格式
117         String nowTime = df.format(dt);
118         long dd = (long) 0;
119         try {
120             dd = df.parse(nowTime).getTime();
121         } catch (Exception e) {
122 
123         }
124         return String.valueOf(dd);
125     }
126 }

  爲了方便解析微信服務器發送給咱們的xml格式的數據,這裏咱們藉助於開源框架dom4j去解析xml(這裏使用的是dom4j-2.0.0-RC1.jar)

  

4.2.在WxServlet的doPost方法中處理請求

  WxServlet的doPost方法的代碼以下:

 1  /**
 2      * 處理微信服務器發來的消息
 3      */
 4     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 5         // TODO 接收、處理、響應由微信服務器轉發的用戶發送給公衆賬號的消息
 6         // 將請求、響應的編碼均設置爲UTF-8(防止中文亂碼)
 7         request.setCharacterEncoding("UTF-8");
 8         response.setCharacterEncoding("UTF-8");
 9         System.out.println("請求進入");
10         String result = "";
11         try {
12             Map<String,String> map = MessageHandlerUtil.parseXml(request);
13             System.out.println("開始構造消息");
14             result = MessageHandlerUtil.buildXml(map);
15             System.out.println(result);
16             if(result.equals("")){
17                 result = "未正確響應";
18             }
19         } catch (Exception e) {
20             e.printStackTrace();
21             System.out.println("發生異常:"+ e.getMessage());
22         }
23         response.getWriter().println(result);
24     }

  到此,咱們的WxServlet已經能夠正常處理用戶的請求並作出響應了.接下來咱們測試一下咱們開發好的公衆號應用是否能夠正常和微信用戶交互

  將WxStudy部署到Tomcat服務器,啓動服務器,記得使用ngrok將本地Tomcat服務器的8080端口映射到外網,保證接口配置信息的URL地址:http://xdp.ngrok.natapp.cn/WxServlet能夠正常與微信服務器通訊

  登陸到咱們的測試公衆號的管理後臺,而後用微信掃描一下測試號的二維碼,以下圖所示:

  

 

  

  

  關注成功後,咱們開發好的公衆號應用會先給用戶發一條提示用戶操做的文本消息,微信用戶根據提示操做輸入"文本",咱們的公衆號應用接收到用戶請求後就給用戶回覆了一條咱們本身構建好的文本消息,以下圖所示:

  

  咱們的公衆號應用響應給微信用戶的文本消息的XML數據以下:

1 <xml>
2   <ToUserName><![CDATA[ojADgs0eDaqh7XkTM9GvDmdYPoDw]]></ToUserName>
3   <FromUserName><![CDATA[gh_43df3882c452]]></FromUserName>
4   <CreateTime>1453755900000</CreateTime>
5   <MsgType><![CDATA[text]]></MsgType>
6   <Content><![CDATA[孤傲蒼狼在學習和總結微信開發了,構建一條文本消息:Hello World!]]></Content>
7 </xml>

  測試公衆號的管理後臺也能夠看到關注測試號的用戶列表,以下圖所示:

  

  經過這個簡單的入門程序,咱們揭開了微信開發的神祕面紗了.

  本篇的內容就這麼多了。本文的內容和代碼參考了用java開發微信公衆號:公衆號接入和access_token管理(二)這篇博客,在此對做者"風的姿態"表示感謝。

  下載測試項目部署運行時,因爲項目中使用的是Servlet3.0,因此要求部署的Tomcat必須是7.x,之前也寫過幾篇關於Servlet3.0的博客,你們有興趣的話能夠去看看,本篇博文對應的測試項目代碼下載

相關文章
相關標籤/搜索