Java微信公眾平台開發(十一)–微信JSSDK中Config配置 (一)在微信公眾平台綁定安全域名(二)後端介面實現JS-SDK配置需要的參數 (三)頁面實現JS-SDk中con

  • 2019 年 10 月 5 日
  • 筆記

JSSDK曾經引爆前端以及後端的工程師,其魔性的力量毋庸置疑,在我們的技術眼裡它的實現原理和根本是不能夠被改變的,這篇文章就不對其js的實現做任何評價和解說了(因為我也不是很懂,哈哈),這裡要說的是它的config配置實現,參考文檔:http://mp.weixin.qq.com/wiki/11/74ad127cc054f6b80759c40f77ec03db.html

微信JS-SDK是微信公眾平檯面向網頁開發者提供的基於微信內的網頁開發工具包,通過使用微信JS-SDK,網頁開發者可藉助微信高效地使用拍照、選圖、語音、位置等手機系統的能力,同時可以直接使用微信分享、掃一掃、卡券、支付等微信特有的能力,為微信用戶提供更優質的網頁體驗;本篇將面向網頁開發者介紹微信JS-SDK如何使用及相關注意事項!JSSDK使用步驟:

  • 步驟一:在微信公眾平台綁定安全域名
  • 步驟二:後端介面實現JS-SDK配置需要的參數
  • 步驟三:頁面實現JS-SDk中config的注入配置,並實現對成功和失敗的處理

(一)在微信公眾平台綁定安全域名

先登錄微信公眾平台進入「公眾號設置」的「功能設置」里填寫「JS介面安全域名」(如下圖),如果需要使用支付類介面,需要確保支付目錄在支付的安全域名下,否則將無法完成支付!(註:登錄後可在「開發者中心」查看對應的介面許可權),因為我用的是測試號,所以登錄以後介面就如下圖:

(二)後端介面實現JS-SDK配置需要的參數

1 wx.config({  2     debug: true, // 開啟調試模式,調用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數,可以在pc端打開,參數資訊會通過log打出,僅在pc端時才會列印。  3     appId: '', // 必填,公眾號的唯一標識  4     timestamp: , // 必填,生成簽名的時間戳  5     nonceStr: '', // 必填,生成簽名的隨機串  6     signature: '',// 必填,簽名,見附錄1  7     jsApiList: [] // 必填,需要使用的JS介面列表  8 });

我們查看js-sdk的配置文檔和以上的程式碼可以發現config的配置需要4個必不可少的參數appId、timestamp、nonceStr、signature,這裡的signature就是我們生成的簽名!

生成簽名之前必須先了解一下jsapi_ticket,jsapi_ticket是公眾號用於調用微信JS介面的臨時票據。正常情況下,jsapi_ticket的有效期為7200秒,通過access_token來獲取。由於獲取jsapi_ticket的api調用次數非常有限,頻繁刷新jsapi_ticket會導致api調用受限,影響自身業務,開發者必須在自己的服務全局快取jsapi_ticket ,所以這裡我們將jsapi_ticket的獲取放到定時任務中,因為它和token的生命周期是一致的,所以在這裡我們將他們放到一起。

①將原有的定時任務WeChatTask中獲取token的程式碼做如下修改:

 1 package com.gede.wechat.common;   2 import java.text.SimpleDateFormat;   3 import java.util.Date;   4 import java.util.HashMap;   5 import java.util.Map;   6   7 import com.gede.web.util.GlobalConstants;   8 import com.gede.wechat.util.HttpUtils;   9  10 import net.sf.json.JSONObject;  11 /**  12 * @author gede  13 * @version date:2019年5月26日 下午7:50:38  14 * @description :  15 */  16 public class WeChatTask {  17     /**  18      * @Description: 任務執行體  19      * @param @throws Exception  20      */  21     public void getToken_getTicket() throws Exception {  22          Map<String, String> params = new HashMap<String, String>();  23          //獲取token執行體  24          params.put("grant_type", "client_credential");  25          params.put("appid", GlobalConstants.getInterfaceUrl("appid"));  26          params.put("secret", GlobalConstants.getInterfaceUrl("AppSecret"));  27          String jstoken = HttpUtils.sendGet(  28                  GlobalConstants.getInterfaceUrl("tokenUrl"), params);  29  30          String access_token = JSONObject.fromObject(jstoken).getString(  31                  "access_token"); // 獲取到token並賦值保存  32          GlobalConstants.interfaceUrlProperties.put("access_token", access_token);  33  34          //獲取jsticket的執行體  35          params.clear();  36          params.put("access_token", access_token);  37          params.put("type", "jsapi");  38          String jsticket = HttpUtils.sendGet(  39                  GlobalConstants.getInterfaceUrl("ticketUrl"), params);  40          String jsapi_ticket = JSONObject.fromObject(jsticket).getString(  41                  "ticket");  42          GlobalConstants.interfaceUrlProperties.put("jsapi_ticket", jsapi_ticket); // 獲取到js-SDK的ticket並賦值保存  43  44          System.out.println("jsapi_ticket================================================" + jsapi_ticket);  45          System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"token為=============================="+access_token);  46     }  47 }

然後我們根據【JS-SDK使用許可權簽名演算法】對參數進行簽名得到signature,這裡的url必須採用前端傳遞到後端,因為每次的url會有所變化,

②所以我們自定義一個許可權簽名演算法JSSDK_Config類,如下:

 1 package com.gede.wechat.common;   2   3 import java.security.MessageDigest;   4 import java.util.Formatter;   5 import java.util.HashMap;   6 import java.util.UUID;   7 import com.gede.web.util.GlobalConstants;   8   9 /**  10 * @author gede  11 * @version date:2019年5月30日 下午2:52:57  12 * @description :  13 */  14 public class JSSDK_Config {  15  16     /**  17      * @Description: 前端jssdk頁面配置需要用到的配置參數  18      * @param @return hashmap {appid,timestamp,nonceStr,signature}  19      * @param @throws Exception  20      * @author gede  21      */  22     public static HashMap<String, String> jsSDK_Sign(String url) throws Exception {  23         String nonce_str = create_nonce_str();  24         String timestamp=GlobalConstants.getInterfaceUrl("timestamp");  25         String jsapi_ticket=GlobalConstants.getInterfaceUrl("jsapi_ticket");  26         // 注意這裡參數名必須全部小寫,且必須有序  27         String  string1 = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + nonce_str  28                 + "&timestamp=" + timestamp  + "&url=" + url;  29         MessageDigest crypt = MessageDigest.getInstance("SHA-1");  30         crypt.reset();  31         crypt.update(string1.getBytes("UTF-8"));  32         String signature = byteToHex(crypt.digest());  33         HashMap<String, String> jssdk=new HashMap<String, String>();  34         jssdk.put("appId", GlobalConstants.getInterfaceUrl("appid"));  35         jssdk.put("timestamp", timestamp);  36         jssdk.put("nonceStr", nonce_str);  37         jssdk.put("signature", signature);  38         return jssdk;  39  40     }  41  42     private static String byteToHex(final byte[] hash) {  43         Formatter formatter = new Formatter();  44         for (byte b : hash) {  45             formatter.format("%02x", b);  46         }  47         String result = formatter.toString();  48         formatter.close();  49         return result;  50     }  51  52     private static String create_nonce_str() {  53         return UUID.randomUUID().toString();  54     }  55  56 }

③編寫使用JSSDK的controller類。新增JssdkController,程式碼如下:

 1 package com.gede.wechat.controller;   2   3 import java.util.Map;   4 import org.springframework.stereotype.Controller;   5 import org.springframework.web.bind.annotation.RequestMapping;   6 import org.springframework.web.bind.annotation.RequestMethod;   7 import org.springframework.web.bind.annotation.RequestParam;   8 import org.springframework.web.bind.annotation.ResponseBody;   9  10  11 /**  12 * @author gede  13 * @version date:2019年5月30日 下午3:03:31  14 * @description :  15 */  16 @Controller  17 @RequestMapping("/jssdk")  18 public class JssdkController {  19     /**  20      * @Description: 前端獲取微信JSSDK的配置參數  21      * @param @param response  22      * @param @param request  23      * @param @param url  24      * @param @throws Exception  25      */  26     @RequestMapping(value="config",method=RequestMethod.POST)  27     @ResponseBody  28     public Message JSSDK_config(  29             @RequestParam(value = "url", required = true) String url) {  30         try {  31             System.out.println(url);  32             Map<String, String> configMap = JSSDK_Config.jsSDK_Sign(url);  33             return Message.success(configMap);  34         } catch (Exception e) {  35             System.out.println("error happened!!!");  36             return Message.error();  37         }  38  39     }  40 }

到這裡我們後端對jssdk的簽名參數的封裝就基本完成了,其中用到了我們自己寫的Message類,程式碼如下:

  1 package com.gede;    2    3 import com.gede.Code;    4    5 /**    6 * @author gede    7 * @version date:2019年5月30日 下午3:09:35    8 * @description :用於消息回復    9 */   10 public class Message {   11     private int code;   12     private String msg;   13     private Object data;   14     public Message() {   15   16     }   17   18     public int getCode() {   19         return code;   20     }   21   22     public void setCode(int code) {   23         this.code = code;   24     }   25   26     public String getMsg() {   27         return msg;   28     }   29   30     public void setMsg(String msg) {   31         this.msg = msg;   32     }   33   34     public Object getData() {   35         return data;   36     }   37   38     public void setData(Object data) {   39         this.data = data;   40     }   41   42     public Message(int code,String msg) {   43         this.code=code;   44         this.msg=msg;   45     }   46   47     public Message(int code,String msg,Object data) {   48         this.code=code;   49         this.msg=msg;   50         this.data=data;   51     }   52     /**   53      * 返回成功消息   54      * @param content 內容   55      * @return 成功消息   56      */   57     public static Message success(String content, Object data) {   58         return new Message(Code.SUCCESS, content, data);   59     }   60     /**   61      * 返回成功消息   62      * @param content 內容   63      * @return 成功消息   64      */   65     public static Message success(String content) {   66         return new Message(Code.SUCCESS, content);   67     }   68     /**   69      * 返回成功消息   70      * @param content 內容   71      * @return 成功消息   72      */   73     public static Message success(Object data) {   74         System.out.println(Code.SUCCESS);   75         return new Message(Code.SUCCESS, "操作成功",data);   76     }   77     /**   78      * 返回成功消息   79      * @param content 內容   80      * @return 成功消息   81      */   82     public static Message success() {   83         return new Message(Code.SUCCESS, "操作成功");   84     }   85     /**   86      * 返回失敗消息   87      * @param content 內容   88      * @return 成功消息   89      */   90     public static Message error(int code,String content, Object data) {   91         return new Message(code, content, data);   92     }   93     /**   94      * 返回失敗消息   95      * @param content 內容   96      * @return 成功消息   97      */   98     public static Message error(String content, Object data) {   99         return new Message(Code.FAIL, content, data);  100     }  101  102     /**  103      * 返回失敗消息  104      * @param content 內容  105      * @return 成功消息  106      */  107     public static Message error(String content) {  108         return new Message(Code.FAIL, content);  109     }  110     /**  111      * 返回失敗消息  112      * @param content 內容  113      * @return 成功消息  114      */  115     public static Message error() {  116         return new Message(Code.FAIL, "操作失敗");  117     }  118  119 }

code類程式碼為:

 1 package com.gede;   2 /**   3 * @author gede   4 * @version date:2019年5月30日 下午3:10:34   5 * @description :狀態碼   6 */   7 public class Code {   8     public static final int SUCCESS = 200; //成功   9     public static final int PARAMATER = 400; //參數錯誤  10     public static final int FAIL =500; //系統異常  11 }

到這裡我們就開始寫前端介面,來響應我們的方法。

(三)頁面實現JS-SDk中config的注入配置,並實現對成功和失敗的處理

這裡在web目錄下新建jssdkconfig.jsp,在jsp頁面用ajax方式獲取並進行配置,並開啟debug模式,打開之後就可以看到配置是否成功的提示,簡單程式碼如下:

 1 <%@ page language="java" contentType="text/html; charset=UTF-8"   2     pageEncoding="UTF-8"%>   3 <!DOCTYPE html >   4 <html>   5 <head>   6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">   7 <meta name="viewport" content="width=device-width" />   8 <title>JSSDk配置</title>   9 <script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>  10 <script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>  11 <script type="text/javascript">  12     function jssdk() {  13         $.ajax({  14             url : "http://zqfbk.iok.la/wechat/wechatconfig/jssdk",  15             type : 'post',  16             dataType : 'json',  17             contentType : "http://zqfbk.iok.la/mychat/jssdk/config",  18             data : {  19                 'url' : kk.split('#')[0]  20             },  21             success : function(data) {  22                 wx.config({  23                     debug : true,  24                     appId : data.data.appId,  25                     timestamp : data.data.timestamp,  26                     nonceStr : data.data.nonceStr,  27                     signature : data.data.signature,  28                     jsApiList : [ 'checkJsApi', 'onMenuShareTimeline',  29                             'onMenuShareAppMessage', 'onMenuShareQQ',  30                             'onMenuShareWeibo', 'hideMenuItems',  31                             'showMenuItems', 'hideAllNonBaseMenuItem',  32                             'showAllNonBaseMenuItem', 'translateVoice',  33                             'startRecord', 'stopRecord', 'onRecordEnd',  34                             'playVoice', 'pauseVoice', 'stopVoice',  35                             'uploadVoice', 'downloadVoice', 'chooseImage',  36                             'previewImage', 'uploadImage', 'downloadImage',  37                             'getNetworkType', 'openLocation', 'getLocation',  38                             'hideOptionMenu', 'showOptionMenu', 'closeWindow',  39                             'scanQRCode', 'chooseWXPay',  40                             'openProductSpecificView', 'addCard', 'chooseCard',  41                             'openCard' ]  42                 });  43             }  44         });  45     }  46  47     function isWeiXin5() {  48         var ua = window.navigator.userAgent.toLowerCase();  49         var reg = /MicroMessenger/[5-9]/i;  50         return reg.test(ua);  51     }  52  53     window.onload = function() {  54         //     if (isWeiXin5() == false) {  55         //           alert("您的微信版本低於5.0,無法使用微信支付功能,請先升級!");  56         //         }  57         jssdk();  58     };  59 </script>  60 </head>  61 <body>  62     <h1>nihao</h1>  63 </body>  64 </html>

(四)pc端進行測試

我的瀏覽器是火狐developer版的,其他的也都差不多,打開瀏覽器按F12,找到一個叫網路的窗口,也有的瀏覽器叫network像我的就是network。

①運行項目後,打開瀏覽器輸入訪問地址http://zqfbk.iok.la/mychat/;點擊Jssdk這裡需要設置一下超鏈接,因為懶得從視圖控制器返回了,超鏈接程式碼:

 <h1>Welcome to Mychat</h1>      <a href="<c:url value="/userinfo" />">UserInfo</a>      <a href="<c:url value="/jssdkconfig.jsp" />">Jssdk</a>

②在我么點擊Jssdk的時候,先按f12 打開network視圖窗口。,然後再點擊,效果圖如下:

③如果你看到你的狀態碼中沒有404,那你多半成功了,我們找對對應的文件名為config的那一行點擊一下,進行查看,此時後台也會做出成功提示,上圖:

如果提示是這樣,那麼標識我們的配置是成功的,那麼到這裡微信jssdk的配置就基本完成了。