Java微信公众平台开发(十一)--微信JSSDK中Config配置
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 + "×tamp=" + 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' : location.href.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的配置就基本完成了。