JAVA微信服務號開發簡記


現在微信公眾平台的開發已經越來越普遍,這次開發需要用到微信公眾平台。所以這邊做一個簡單的記錄,也算是給那些沒踩過坑的童鞋一些啟示吧。我將分幾塊來簡單的描述一下,之后會做詳細的說明。

 

基本認證信息說明

首先。微信分為了幾個不同的號。有訂閱號、服務號、企業號。

其中訂閱號是免費的。其他都是要錢的。免費的基本上只能發發信息。

要錢的功能比較全面。基本上微信的接口都能調用了。這里我也主要開發的是服務號。

如果要申請服務號微信也是明碼標價,300塊一次,一年一次。(收錢真狠)

簡單的說,如果你沒有交錢那么很多功能是無法使用的。

 

功能性說明

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

普遍的有用戶的昵稱性別地理位置等。

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

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

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

 

接口調用說明

微信的接口有幾種不同的類型:

1、get請求,微信會提供一個地址,然后你直接在這個地址后面加上參數即可調用接口

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

3、回調請求,微信在收到用戶消息或者別的觸發條件成立時調用用戶設置的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

1、生成地址

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的寫法:

/**
     * 微信獲取openId
     */
    @RequestMapping(value="/weiXin", method=RequestMethod.GET)
    public String weiXin(HttpServletRequest request)
    {
        //獲取用戶openId
        String openId = "";
        
        //用戶同意授權,獲取返回值code和state
        String code = request.getParameter("code");
        //如果code為空則(請自己實現判斷,這里是簡寫)
        if(code == null){
            return "index";
        }
        
        //獲取openid的地址
        String getOpenidUri = "https://api.weixin.qq.com/sns/oauth2/access_token"
                + "?appid=" + AppID
                + "&secret=" + AppSecret
                + "&code=" + code
                + "&grant_type=authorization_code";
        try{
             //發送請求獲取返回參數,使用java原生實現,可以使用httpclient或者第三方庫實現
               URL getOpenidUrl = new URL(getOpenidUri);
             HttpURLConnection openidConnection = (HttpURLConnection) getOpenidUrl.openConnection(); 
             openidConnection.connect();
             
             BufferedReader openidReader = new BufferedReader(new InputStreamReader(openidConnection.getInputStream())); 
             StringBuffer openidStringBuffer = new StringBuffer();
             String openidLines; 
             while ((openidLines = openidReader.readLine()) != null) { 
                 openidStringBuffer.append(openidLines);
             } 
             openidReader.close(); 
             openidConnection.disconnect(); 
             
             //返回的參數是json格式
               JSONObject openidJson = JSONObject.parseObject(openidStringBuffer.toString());
             if(openidJson.containsKey("openid")){
                 openId = openidJson.getString("openid");
             }
        }catch(Exception e){
            //連接異常,請求異常,或者json返回值異常均需要處理
        }
        
        //需要對openId判空,請自行處理
         System.out.println(openId);
        return "index";
    }

當微信回調你這個地址之后按照上述代碼執行后即可獲取到openId,上述代碼只是參考,實際中需要改進很多判斷以及對很多錯誤情況的預判。你也可以根據接口文檔詳細書寫。

 

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

checkoutURL

之前說過,在設置URL的時候會有一個核對的過程,你需要給出你的接口地址,然后返回一個參數驗證過后微信才會同意你修改這個URL

下面是checkout的代碼,因為涉及到加密所以需要多多注意

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
//工具類,之后會被調用
public class CheckoutUtil {
    // 與接口配置信息中的Token要一致
    private static String token = "xxxxxxxxxxx";

    /**
     * 驗證簽名
     * 
     * @param signature
     * @param timestamp
     * @param nonce
     * @return
     */
    public static boolean checkSignature(String signature, String timestamp, String nonce) {
        String[] arr = new String[] { token, timestamp, nonce };
        // 將token、timestamp、nonce三個參數進行字典序排序
        // Arrays.sort(arr);
        sort(arr);
        StringBuilder content = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            content.append(arr[i]);
        }
        MessageDigest md = null;
        String tmpStr = null;

        try {
            md = MessageDigest.getInstance("SHA-1");
            // 將三個參數字符串拼接成一個字符串進行sha1加密
            byte[] digest = md.digest(content.toString().getBytes());
            tmpStr = byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        content = null;
        // 將sha1加密后的字符串可與signature對比,標識該請求來源於微信
        return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
    }

    /**
     * 將字節數組轉換為十六進制字符串
     * 
     * @param byteArray
     * @return
     */
    private static String byteToStr(byte[] byteArray) {
        String strDigest = "";
        for (int i = 0; i < byteArray.length; i++) {
            strDigest += byteToHexStr(byteArray[i]);
        }
        return strDigest;
    }

    /**
     * 將字節轉換為十六進制字符串
     * 
     * @param mByte
     * @return
     */
    private static String byteToHexStr(byte mByte) {
        char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
        char[] tempArr = new char[2];
        tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
        tempArr[1] = Digit[mByte & 0X0F];
        String s = new String(tempArr);
        return s;
    }
    public static void sort(String a[]) {
        for (int i = 0; i < a.length - 1; i++) {
            for (int j = i + 1; j < a.length; j++) {
                if (a[j].compareTo(a[i]) < 0) {
                    String temp = a[i];
                    a[i] = a[j];
                    a[j] = temp;
                }
            }
        }
    }
}
@RequestMapping(value="/weixinTest")
    public void weixinTest(HttpServletRequest request) throws Exception{
        boolean isGet = request.getMethod().toLowerCase().equals("get");
        PrintWriter print;
        if (isGet) {
            // 微信加密簽名
            String signature = request.getParameter("signature");
            // 時間戳
            String timestamp = request.getParameter("timestamp");
            // 隨機數
            String nonce = request.getParameter("nonce");
            // 隨機字符串
            String echostr = request.getParameter("echostr");
            // 通過檢驗signature對請求進行校驗,若校驗成功則原樣返回echostr,表示接入成功,否則接入失敗
            if (signature != null && CheckoutUtil.checkSignature(signature, timestamp, nonce)) {
                try {
                    print = response.getWriter();
                    print.write(echostr);
                    print.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

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;
    }
}

這邊以獲取地理位置為例(需要在微信后台手動開啟這個功能哦)

@RequestMapping(value="/weixinTest")
    public void weixinTest(HttpServletRequest request) throws Exception{
        // 調用parseXml方法解析請求消息
        Map<String, String> requestMap = MessageUtil.parseXml(request);
        // 發送方帳號
        String fromUserName = requestMap.get("FromUserName");
        log.error("----------------------------------------------" + fromUserName);
        // 開發者微信號
        String toUserName = requestMap.get("ToUserName");
        // 消息類型
        String msgType = requestMap.get("MsgType");
        
        if ("event".equals(msgType)){
            log.error("----------------------------------------------" +msgType);
            String Latitude = requestMap.get("Latitude");
            log.error("----------------------------------------------" +Latitude);
            String Longitude = requestMap.get("Longitude");
            log.error("----------------------------------------------" +Longitude);
            
        }
}

 

需要注意的點

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

2、checkout不要刪除,修改地址時需要使用,當地址穩定后項目上線之后直接刪除。

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

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

5、所有測試均需要在服務器上完成,也就需要外網可以被訪問的域名和地址。

6、微信給的權限很多,需要自己看清楚,有的權限是有次數限制的。

7、盡可能把一些參數封裝一下,避免代碼冗長。

8、所有測試完成后請換成密文形式,不然用戶的信息可能泄露。

9、以上所有代碼僅供參考,實際中還需要添磚加瓦,大改特改。

10、服務器上調試日志很重要。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM