本文主要介绍了SpringBoot 基于JS-SDK实现自定义微信分享,并通过本地测试的方式进行调试,文中通过微信实现分享流程及示例代码进行非常详细的介绍,希望本文对开发爱好者学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧!
一 准备工作
1.微信公众平台appID和appsecret
2.微信开发文档(相当烂,但一定要看)
3.微信web开发者工具
二 开发步骤
1.申请接口测试号并进行JS接口安全域名设置
接口测试号申请。点击访问 ,选择接口测试号申请,如下图所示:
或者直接访问 :申请测试账号页面 如下图所示:
点击登录进行扫码登录,如下图所示:
登录后如下图所示:
配置JS接口安全域名
2.windows下配置本地回环地址
找到windows系统中 hosts 文件,配置回环地址的域名,C:\Windows\System32\drivers\etc
配置回环地址
3. 下载微信web开发者工具,可以在PC 进行测试
下载微信web开发者工具,点击访问下载页面 如下图所示:
下载完成之后,安装微信web开发者工具,一步一步傻瓜式安装。
4.参照微信开发文档实现
点击访问微信JS-SDK说明文档 如下图所示:
JSSDK使用步骤
步骤一:绑定域名(上面已经操作了)
步骤二:引入JS文件(下面实战代码中会介绍到如何使用)
步骤三:通过config接口注入权限验证配置(下面实战代码中会介绍到如何使用)
步骤四:通过ready接口处理成功验证
步骤五:通过error接口处理失败验证
接口调用说明
5.代码实现
上面步骤步骤三中的 signature是一个重要的参数,生成它需要获取 jsapi_ticket,而生成 jsapi_ticket 需要通过 access_token。
获取signature流程如下:
- 获取 access_token 然后根据 access_token 获取 jsapi_ticket 。
- 排序 noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳),url(当前网页的URL,不包含#及其后面部分)4个参数拼接例如:noncestr=XX&jsapi_ticket=XX&jtimestamp=XX&jurl=XX
- 然后通过sha1加密拼接的4个参数获取到signature
初始化微信JSSDK配置信息
1 @Controller
2 @RequestMapping("/weixin")
3 public class WeiXinDemoController {
4
5 @Autowired
6 private WeiXinService weiXinService;
7 @Autowired
8 private WXConfig weiXinConfig;
9
10
11 /**
12 * 初始化微信JSSDK配置信息
13 * @param request
14 * @param response
15 * @param shareUrl 分享地址
16 * @return
17 * @throws Exception
18 */
19 @RequestMapping("/initWXJSSDKConfigInfo")
20 @ResponseBody
21 public String initWXJSConfig (HttpServletRequest request, HttpServletResponse response, String shareUrl) throws Exception{
22 Map map = weiXinService.initJSSDKConfigInfo(shareUrl);
23 String json = weiXinService.mapToJson(map);
24 return json;
25 }
26 }
初始化JSSDK配置信息,配置信息有:noncestr(随机字符串)、有效的jsapi_ticket、timestamp(时间戳)、shareUrl(当前网页的URL,不包含#及其后面部分)appid(公众号 appid)
1 /**
2 * @description 初始化JSSDK配置信息
3 * @param shareUrl 分享的url地址
4 * @return
5 * @throws Exception
6 */
7 public Map initJSSDKConfigInfo(String shareUrl) throws Exception {
8 String accessToken = this.getJSSDKAccessToken();
9 String jsapiTicket = this.getJSSDKJsapiTicket(accessToken);
10 String timestamp = Long.toString(System.currentTimeMillis() / 1000);
11 String nonceStr = UUID.randomUUID().toString();
12 String signature = this.buildJSSDKSignature(jsapiTicket,timestamp,nonceStr,shareUrl);
13 Map<String,String> map = new HashMap<String,String>();
14 map.put("shareUrl", shareUrl);
15 map.put("jsapi_ticket", jsapiTicket);
16 map.put("nonceStr", nonceStr);
17 map.put("timestamp", timestamp);
18 map.put("signature", signature);
19 map.put("appid", weiXinConfig.getAppID());
20 return map;
21 }
获取 JSSDK access_token
1 /**
2 * @description 获取JSSDK的认证token
3 * @return 返回JSSDK的认证token
4 */
5 public String getJSSDKAccessToken() {
6 String token = null;
7 String url = WXContants.JSSDK_ACCESSTOKEN.replaceAll(WXContants.REPLACE_FEILD_APPID,
8 weiXinConfig.getAppID()).replaceAll(WXContants.REPLACE_FEILD_APPSECRET,
9 weiXinConfig.getAppsecret());
10 String json = postRequestForWeiXinService(url);
11 Map map = jsonToMap(json);
12 if (map != null) {
13 token = (String) map.get("access_token");
14 }
15 return token;
16 }
获取 JSSDK jsapi_ticket
1 /**
2 * @description 获取JSSDK的ticket
3 * @param token JSSDK的认证token
4 * @return 返回JSSDK的ticket
5 */
6 public String getJSSDKJsapiTicket(String token) {
7 String url = WXContants.JSSDK_TICKET.replaceAll(WXContants.REPLACE_FEILD_ACCESS_TOKEN, token);
8 String json = postRequestForWeiXinService(url);
9 Map map = jsonToMap(json);
10 String ticket = null;
11 if (map != null) {
12 ticket = (String) map.get("ticket");
13 }
14 return ticket;
15 }
拼接 noncestr(随机字符串), 有效的jsapi_ticket、 timestamp(时间戳)、url(当前网页的URL,不包含#及其后面部分)并通过sha1进行加密
1 /**
2 * @description 构建分享链接的签名
3 * @param ticket
4 * @param nonceStr
5 * @param timestamp
6 * @param url
7 * @return
8 * @throws Exception
9 */
10 public static String buildJSSDKSignature(String ticket,String timestamp,String nonceStr ,String url) throws Exception {
11 StringBuffer signaStr = new StringBuffer();
12 signaStr.append("jsapi_ticket=").append(ticket);
13 signaStr.append("&noncestr=").append(nonceStr);
14 signaStr.append("×tamp=").append(timestamp);
15 signaStr.append("&url=").append(url);
16 return sha1(signaStr.toString());
17 }
18
19 /**
20 * @description sha1 加密JSSDK微信配置参数获取签名
21 * @param signaStr 构建分享链接的签名
22 * @return 返回加密签名
23 */
24 public static String sha1(String signaStr) throws Exception {
25 MessageDigest md = MessageDigest.getInstance("SHA-1");
26 byte[] digest = md.digest(signaStr.getBytes());
27 return byteToStr(digest).toLowerCase();
28 }
29 /**
30 * @description 将字节数组转换为十六进制字符串
31 * @param byteArray 待转换的字节数组
32 * @return
33 */
34 private static String byteToStr(byte[] byteArray) {
35 String strDigest = "";
36 for (int i = 0; i < byteArray.length; i++) {
37 strDigest += byteToHexStr(byteArray[i]);
38 }
39 return strDigest;
40 }
41
42 /**
43 * @description 将字节转换为十六进制字符串
44 * @param mByte
45 * @return
46 */
47 private static String byteToHexStr(byte mByte) {
48 char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
49 char[] tempArr = new char[2];
50 tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
51 tempArr[1] = Digit[mByte & 0X0F];
52 String s = new String(tempArr);
53 return s;
54 }
基础工具方法
1 /**
2 * @description 将map转换成json字符串
3 * @param map map对象
4 * @return json字符串
5 */
6 public String mapToJson(Map map){
7 Gson gson = new Gson();
8 String json = gson.toJson(map);
9 return json;
10 }
11
12 /**
13 * @description 将json字符串转换成map字符串
14 * @param json json字符串
15 * @return map对象
16 */
17 private Map jsonToMap(String json) {
18 Gson gons = new Gson();
19 Map map = gons.fromJson(json, new TypeToken<Map>(){}.getType());
20 return map;
21 }
22
23
24 private String postRequestForWeiXinService(String accessTokenUrl) {
25 ResponseEntity<String> postForEntity = restTemplate.postForEntity(accessTokenUrl, null, String.class);
26 String json = postForEntity.getBody();
27 return json;
28 }
29
30 private String getRequestForWeiXinService(String getUserInfoUrl) {
31 ResponseEntity<String> postForEntity = restTemplate.getForEntity(getUserInfoUrl.toString(), String.class);
32 String json = postForEntity.getBody();
33 return json;
34 }
wxShare.js 主要是获取JSSDK配置信息并定义分享功能处理。具体代码如下:
1 /***用户点击分享到微信圈后加载接口接口*******/
2 $.post("/weixin/initWXJSSDKConfigInfo",{"shareUrl":window.location.href.split('#')[0]},function(data,status){
3 data=eval("("+data+")");
4 wx.config({
5 debug: false,
6 appId: data.appid,
7 timestamp:data.timestamp,
8 nonceStr:data.nonceStr,
9 signature:data.signature,
10 jsApiList: [
11 'checkJsApi',
12 'onMenuShareTimeline',
13 'onMenuShareAppMessage',
14 'onMenuShareQQ',
15 'onMenuShareWeibo',
16 'onMenuShareQZone',
17 //'updateAppMessageShareData',
18 //'updateTimelineShareData',
19 //'hideOptionMenu',
20 ]
21 });
22 var shareTitle = $("#wx_share_span").data("shareTitle");
23 if(!shareTitle){
24 shareTitle = $("title").html();
25 }
26 var shareImg = $("#wx_share_span").data("shareImg");
27 if(!shareImg){
28 //shareImg = common.bp()+'/m_images/shareImg.jpg';
29 }
30 var shareLink = $("#wx_share_span").data("shareLink");
31 if(!shareLink){
32 shareLink = window.location.href.split('#')[0];
33 }
34 var shareDesc = $("#wx_share_span").data("shareDesc");
35 if(!shareDesc){
36 shareDesc = $("meta[name=description]").attr("content");
37 }
38 wx.ready(function(){
39 // alert("准备分享");
40 wx.onMenuShareTimeline({
41 title : shareTitle, // 分享标题
42 link : shareLink, // 分享链接
43 imgUrl : shareImg, // 分享图标
44 success : function() {
45 // 用户确认分享后执行的回调函数
46 //alert("分享成功");
47 },
48 cancel : function() {
49 // 用户取消分享后执行的回调函数
50 //alert("分享取消");
51 }
52 });
53 //wx.hideOptionMenu();/!***隐藏分享菜单****!/
54 wx.onMenuShareAppMessage({
55 title: shareTitle, // 分享标题
56 desc: shareDesc, // 分享描述
57 link: shareLink, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
58 imgUrl: shareImg, // 分享图标
59 success: function () {
60 // 用户确认分享后执行的回调函数
61 },
62 cancel: function () {
63 // 用户取消分享后执行的回调函数
64 }
65 });
66 wx.onMenuShareQQ({
67 title: shareTitle, // 分享标题
68 desc: shareDesc, // 分享描述
69 link: shareLink, // 分享链接
70 imgUrl: shareImg, // 分享图标
71 success: function () {
72 // 用户确认分享后执行的回调函数
73 },
74 cancel: function () {
75 // 用户取消分享后执行的回调函数
76 }
77 });
78 wx.onMenuShareQZone({
79 title: shareTitle, // 分享标题
80 desc: shareDesc, // 分享描述
81 link: shareLink, // 分享链接
82 imgUrl: shareImg, // 分享图标
83 success: function () {
84 // 用户确认分享后执行的回调函数
85 },
86 cancel: function () {
87 // 用户取消分享后执行的回调函数
88 }
89 });
90 Wx.checkJsApi({
91 jsApiList: ['updateAppMessageShareData','updateTimelineShareData','onMenuShareWeibo'], // 需要检测的JS接口列表,所有JS接口列表见附录2,
92 success: function(res) {
93 // 以键值对的形式返回,可用的api值true,不可用为false
94 // 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}
95 }
96 });
97 //wx.hideOptionMenu();/!***隐藏分享菜单****!/
98 wx.updateAppMessageShareData({
99 title: shareTitle, // 分享标题
100 desc: shareDesc, // 分享描述
101 link: shareLink, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
102 imgUrl: shareImg, // 分享图标
103 success: function () {
104 // 用户确认分享后执行的回调函数
105 },
106 cancel: function () {
107 // 用户取消分享后执行的回调函数
108 }
109 });
110 wx.updateTimelineShareData({
111 title: shareTitle, // 分享标题
112 link: shareLink, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
113 imgUrl: shareImg, // 分享图标
114 success: function () {
115 // 用户确认分享后执行的回调函数
116 },
117 cancel: function () {
118 // 用户取消分享后执行的回调函数
119 }
120 });
121 wx.onMenuShareWeibo({
122 title: shareTitle, // 分享标题
123 desc: shareDesc, // 分享描述
124 link: shareLink, // 分享链接
125 imgUrl: shareImg, // 分享图标
126 success: function () {
127 // 用户确认分享后执行的回调函数
128 },
129 cancel: function () {
130 // 用户取消分享后执行的回调函数
131 }
132 });
133 });
134 });
分享页面该页面需要引入wxShare.js和jweixin-1.6.0.js,并且通过在隐藏的span标签上定义自定义分享的内容,具体代码如下:
1 <!DOCTYPE html>
2 <html xmlns:th="http://www.thymeleaf.org">
3 <head>
4 <meta charset="UTF-8">
5 <title>微信JS-SDK分享</title>
6 <script type="text/javascript" th:src="@{/js/jquery-1.8.3.min.js}" ></script>
7 <script type="text/javascript" th:src="@{/js/wxShare.js}"></script>
8 <script type="text/javascript" src="http://res2.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
9 </head>
10 <body>
11 <span id="wx_share_span" style="display: none"></span>
12 <h1>SpringMVC + Thymeleaf Hello World example</h1>
13 <p th:text="${content}"></p> <!-- ${...}变量表达式 -->
14 <script type="text/javascript">
15 $(document).ready(function(){
16 $("#wx_share_span").data("shareTitle", "微信JS-SDK分享");
17 $("#wx_share_span").data("shareDesc", "一个简单的基于微信JS-SDK分享的demo");
18 //$("#wx_share_span").data("shareLink", "/wxShare");
19 $("#wx_share_span").data("shareImg", "http://www.zcg.com:8090/img/img.png");
20 });
21 </script>
22 </body>
23 </html>
6.测试
打开微信开发者工具,在地址栏输入http://www.zcg.com:8090/weixin/wxShare,点击分享,能够出现以下界面,说明已经可以实现分享了!