Java微信公衆號開發梳理

Java微信公衆號開發梳理

如今微信公衆平臺的開發已經愈來愈廣泛,此次開發須要用到微信公衆平臺。所以作一個簡單的記錄,也算是給那些沒踩過坑的童鞋一些啓示吧。我將分幾塊來簡單的描述一下,以後會作詳細的說明。html

功能性說明

微信提供了許許多多的接口供用戶使用,開發者能夠根據這些接口獲取用戶的信息。java

廣泛的有用戶的暱稱性別地理位置等。git

其餘我就不一一列舉了,總之須要根據你的實際業務需求來進行使用。spring

你須要什麼就去看看微信是否提供了相應的接口供你使用。json

微信接口文檔地址路徑:https://mp.weixin.qq.com/wiki/home/index.htmlapi

接口調用說明

微信的接口有幾種不一樣的類型:數組

一、get請求,微信會提供一個地址,而後你直接在這個地址後面加上參數便可調用接口瀏覽器

二、post請求,微信提供一個地址,你須要向這個接口地址傳入相應的參數。tomcat

三、回調請求,微信在收到用戶消息或者別的觸發條件成立時調用用戶設置的URL地址。安全

請求格式包括XML和json,須要根據接口文檔來。任何語言都可,JS有微信專門的JS-SDK。

我使用的是JAVA

關鍵詞說明

OpenID:用戶在你這個公衆號上的惟一標識(我這邊的處理是與項目中用戶的UserId進行綁定,這樣也就實現了用戶在你的平臺進行綁定)

access_token :注意,這裏我把這個名字換一下,「ACCESS_TOKEN」爲了和以後的分開。這個東西是一個全局量,當你須要調用特定的微信接口時,微信會驗證你是否有權限,你就須要傳這個值給微信。注意!!獲取access_token是有次數限制的,可是access_token 的過時時間很長,因此在沒有過時的狀況下請勿重複獲取。

access_token:這個和我稱做小寫的access_token和大寫的不同,這個是用戶鑑權時使用,獲取這個小寫的access_token是沒有次數限制的,這個東西能只是用於獲取用戶openId時使用。(新手千萬要區分不一樣的access_token以避免出現問題)

開發者填寫的URL:接口文檔出現這個的時候一開始我也很懵比,這裏的URL是指,當用戶若是進行特定的操做,如:發送給公衆號消息,進入公衆號,等等,微信會把一些參數傳入這個URL。舉個例子,若是用戶發送給公衆號一個字符。那麼公衆號會把這個字符轉發給你這個URL,而後你這個URL接到微信給你的發的信息,你就能夠返回給用戶信息了。

這個URL是在這裏設置的:

image

這裏的服務器地址URL就是

其中微信有兩個信息比較重要,第一微信會告訴你這是用戶的什麼事件,第二是哪一個用戶也就是用戶的openId

 

網頁受權域名:

image

在這裏必須設置網頁的受權域名,不然用戶在微信公衆號中對於你的域名下的地址將不信任。

開發三步走

這是創建在你已經作好準備的狀況下是三步,若是你連公衆號服務器域名都沒有的話就不僅了。

第一步、網頁受權域名

image

下載對應文件,配置在tomcat你的項目的根目錄下。

保證:域名/下載的文件名。這個地址能訪問到,能在瀏覽器中顯示文字便可。

第二步、獲取openId

文檔中在:https://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html

一、生成地址

https://open.weixin.qq.com/connect/oauth2/authorize?(這個是不動的) 
appid=xxxxxxxxxx(這個是你的appid) 
&redirect_uri=http%3a%2f%2fwww.xxxxxxx.com%xxxxxxxx%2fweixxxxxit%2fxxxxx(這個是你的回調地址,須要URL編碼) 
&response_type=code(不動) 
&scope=snsapi_base(若是隻要獲取openId就不動,須要別的參考文檔) 
#wechat_redirect(不動)

最終地址相似:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=xxxxxxxxxx&redirect_uri=http%3a%2f%2fwww.xxxxxxx.com%xxxxxxxx%2fweixxxxxit%2fxxxxx&response_type=code&scope=snsapi_base#wechat_redirect

用戶訪問這個地址,微信就會回調你的回調地址,你在回調地址中就能夠獲取到openId了

回調地址中springMVC的寫法:

 1 /**
 2      * 微信獲取openId
 3      */
 4     @RequestMapping(value="/weiXin", method=RequestMethod.GET)
 5     public String weiXin(HttpServletRequest request)
 6     {
 7         //獲取用戶openId
 8         String openId = "";
 9         
10         //用戶贊成受權,獲取返回值code和state
11         String code = request.getParameter("code");
12         //若是code爲空則(請本身實現判斷,這裏是簡寫)
13         if(code == null){
14             return "index";
15         }
16         
17         //獲取openid的地址
18         String getOpenidUri = "https://api.weixin.qq.com/sns/oauth2/access_token"
19                 + "?appid=" + AppID
20                 + "&secret=" + AppSecret
21                 + "&code=" + code
22                 + "&grant_type=authorization_code";
23         try{
24              //發送請求獲取返回參數,使用java原生實現,可使用httpclient或者第三方庫實現
25                URL getOpenidUrl = new URL(getOpenidUri);
26              HttpURLConnection openidConnection = (HttpURLConnection) getOpenidUrl.openConnection(); 
27              openidConnection.connect();
28              
29              BufferedReader openidReader = new BufferedReader(new InputStreamReader(openidConnection.getInputStream())); 
30              StringBuffer openidStringBuffer = new StringBuffer();
31              String openidLines; 
32              while ((openidLines = openidReader.readLine()) != null) { 
33                  openidStringBuffer.append(openidLines);
34              } 
35              openidReader.close(); 
36              openidConnection.disconnect(); 
37              
38              //返回的參數是json格式
39                JSONObject openidJson = JSONObject.parseObject(openidStringBuffer.toString());
40              if(openidJson.containsKey("openid")){
41                  openId = openidJson.getString("openid");
42              }
43         }catch(Exception e){
44             //鏈接異常,請求異常,或者json返回值異常均須要處理
45         }
46         
47         //須要對openId判空,請自行處理
48          System.out.println(openId);
49         return "index";
50     }
View Code

當微信回調你這個地址以後按照上述代碼執行後便可獲取到openId,上述代碼只是參考,實際中須要改進不少判斷以及對不少錯誤狀況的預判。你也能夠根據接口文檔詳細書寫。

第三步、微信調用接口設計

checkoutURL

以前說過,在設置URL的時候會有一個核對的過程,你須要給出你的接口地址,而後返回一個參數驗證事後微信纔會贊成你修改這個URL

下面是checkout的代碼,由於涉及到加密因此須要多多注意

 1 import java.security.MessageDigest;
 2 import java.security.NoSuchAlgorithmException;
 3 //工具類,以後會被調用
 4 public class CheckoutUtil {
 5     // 與接口配置信息中的Token要一致
 6     private static String token = "xxxxxxxxxxx";
 7 
 8     /**
 9      * 驗證簽名
10      * 
11      * @param signature
12      * @param timestamp
13      * @param nonce
14      * @return
15      */
16     public static boolean checkSignature(String signature, String timestamp, String nonce) {
17         String[] arr = new String[] { token, timestamp, nonce };
18         // 將token、timestamp、nonce三個參數進行字典序排序
19         // Arrays.sort(arr);
20         sort(arr);
21         StringBuilder content = new StringBuilder();
22         for (int i = 0; i < arr.length; i++) {
23             content.append(arr[i]);
24         }
25         MessageDigest md = null;
26         String tmpStr = null;
27 
28         try {
29             md = MessageDigest.getInstance("SHA-1");
30             // 將三個參數字符串拼接成一個字符串進行sha1加密
31             byte[] digest = md.digest(content.toString().getBytes());
32             tmpStr = byteToStr(digest);
33         } catch (NoSuchAlgorithmException e) {
34             e.printStackTrace();
35         }
36         content = null;
37         // 將sha1加密後的字符串可與signature對比,標識該請求來源於微信
38         return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
39     }
40 
41     /**
42      * 將字節數組轉換爲十六進制字符串
43      * 
44      * @param byteArray
45      * @return
46      */
47     private static String byteToStr(byte[] byteArray) {
48         String strDigest = "";
49         for (int i = 0; i < byteArray.length; i++) {
50             strDigest += byteToHexStr(byteArray[i]);
51         }
52         return strDigest;
53     }
54 
55     /**
56      * 將字節轉換爲十六進制字符串
57      * 
58      * @param mByte
59      * @return
60      */
61     private static String byteToHexStr(byte mByte) {
62         char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
63         char[] tempArr = new char[2];
64         tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
65         tempArr[1] = Digit[mByte & 0X0F];
66         String s = new String(tempArr);
67         return s;
68     }
69     public static void sort(String a[]) {
70         for (int i = 0; i < a.length - 1; i++) {
71             for (int j = i + 1; j < a.length; j++) {
72                 if (a[j].compareTo(a[i]) < 0) {
73                     String temp = a[i];
74                     a[i] = a[j];
75                     a[j] = temp;
76                 }
77             }
78         }
79     }
80 }
View Code
 1 @RequestMapping(value="/weixinTest")
 2     public void weixinTest(HttpServletRequest request) throws Exception{
 3         boolean isGet = request.getMethod().toLowerCase().equals("get");
 4         PrintWriter print;
 5         if (isGet) {
 6             // 微信加密簽名
 7             String signature = request.getParameter("signature");
 8             // 時間戳
 9             String timestamp = request.getParameter("timestamp");
10             // 隨機數
11             String nonce = request.getParameter("nonce");
12             // 隨機字符串
13             String echostr = request.getParameter("echostr");
14             // 經過檢驗signature對請求進行校驗,若校驗成功則原樣返回echostr,表示接入成功,不然接入失敗
15             if (signature != null && CheckoutUtil.checkSignature(signature, timestamp, nonce)) {
16                 try {
17                     print = response.getWriter();
18                     print.write(echostr);
19                     print.flush();
20                 } catch (IOException e) {
21                     e.printStackTrace();
22                 }
23             }
24         }
25     }
View Code

URL:http://www.xxxxxxxx.com/weixinTest/

Token:xxxxxxxxxxxx

相似上面

測試時使用兼容模式,等測試完成後使用安全模式,微信提供了AES的加密解密工具類

https://mp.weixin.qq.com/wiki/1/5dc395cdeb98e9d23a8541cf0bab38ad.html

 

最後微信調用URL

須要解析XML,也就順帶加個工具類須要使用相應dom4j的jar

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

public class MessageUtil {
    public static Map parseXml(HttpServletRequest request) throws Exception {
        // 將解析結果存儲在HashMap中
        Map map = new HashMap();
 
        // 從request中取得輸入流
        InputStream inputStream = request.getInputStream();
        
        // 讀取輸入流
        SAXReader reader = new SAXReader();
        Document document = reader.read(inputStream);
        // 獲得xml根元素
        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;
    }
}
View Code

這邊以獲取地理位置爲例(須要在微信後臺手動開啓這個功能哦)

 1 @RequestMapping(value="/weixinTest")
 2     public void weixinTest(HttpServletRequest request) throws Exception{
 3         // 調用parseXml方法解析請求消息
 4         Map<String, String> requestMap = MessageUtil.parseXml(request);
 5         // 發送方賬號
 6         String fromUserName = requestMap.get("FromUserName");
 7         log.error("----------------------------------------------" + fromUserName);
 8         // 開發者微信號
 9         String toUserName = requestMap.get("ToUserName");
10         // 消息類型
11         String msgType = requestMap.get("MsgType");
12         
13         if ("event".equals(msgType)){
14             log.error("----------------------------------------------" +msgType);
15             String Latitude = requestMap.get("Latitude");
16             log.error("----------------------------------------------" +Latitude);
17             String Longitude = requestMap.get("Longitude");
18             log.error("----------------------------------------------" +Longitude);
19             
20         }
21 }
View Code

須要注意的點

一、看清接口文檔,仔細理解

二、checkout不要刪除,修改地址時須要使用,當地址穩定後項目上線以後直接刪除。

三、微信調用URL會被用戶平凡訪問,向我這樣寫確定是不對的,若是你的用戶量大負載均衡確定是必須的。

四、微信接口雖然穩定,可是仍是要注意處理意外請求,處理一些可能會出現的錯誤狀況。不然當出現沒有這個參數而你去取,很容易致使異常。

五、全部測試均須要在服務器上完成,也就須要外網能夠被訪問的域名和地址。

六、微信給的權限不少,須要本身看清楚,有的權限是有次數限制的。

七、儘量把一些參數封裝一下,避免代碼冗長。

八、全部測試完成後請換成密文形式,否則用戶的信息可能泄露。

九、以上全部代碼僅供參考,實際中還須要添磚加瓦,大改特改。

十、服務器上調試日誌很重要。

相關文章
相關標籤/搜索