大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
微信网页分享–配合微信公众平台
一. 准备工作
-
准备一个域名(微信分享出去的合法链接都是挂载在域名下的,服务器的ip名是不行的),能用内网穿透的也可以(我测试阶段就是用的内网穿透的方法)。内网穿透方法可以见章节末尾参考的链接。
-
在微信公众平台准备一个账号
- 设置公众号的js安全域名(把域名放进去,不用加http的前缀)
- 设置公众号的js安全域名(把域名放进去,不用加http的前缀)
保存之前要把文件下载下来放到项目根目录下,如果是开发环境的springboot项目
可以参照这个教程做
`https://www.cnblogs.com/pxblog/p/13445128.htm`
- 设置公众号开发信息(拿到
AppID
和AppSecret
)
同时在`IP`白名单设置相关`ip`地址,最后才能成功获取`access_token`
注:开发阶段白名单添加本机所在ip地址,生产阶段添加云服务器所在ip地址
- 微信公众平台没有相关账号的,可以用微信号使用测试账号进行开发
https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login&token=840340790&lang=zh_CN
测试账号的测试详情可参考一下大佬的流程:https://zhuanlan.zhihu.com/p/134461089
注:使用测试账号接口,获取access_token这一步是可以正常操作的,但到后面分享朋友及朋友圈阶段就会报错,还是得用公众平台账号。
二. SpringBoot前后端不分离版本
-
属性文件application.yml中配置
AppID
和AppSecret
-
初始化
JSSDK
配置信息,参考官方文档https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#3
JSSDK
使用步骤,最重要的是要生成签名signature
获取signature流程如下:
-
前端将要分享的
url
请求给后端 -
获取
access_token
,然后根据access_token
向微信官方Api
获取jsapi_ticket
-
排序
noncestr
(随机字符串), 有效的jsapi_ticket
,timestamp
(时间戳),url
(当前网页的URL,不包含#及其后面部分)4个参数拼接,例如:noncestr=XX&jsapi_ticket=XX×tamp=XX&url=XX
-
然后通过
sha1加密
拼接的4个参数得到signature
注:
-
如上图所示,
JSSDK
配置信息需要有:noncestr(随机字符串)、有效的signature(签名)、timestamp(时间戳)、appid(公众号appid),后端生成所需的配置信息并返回给前端,前端拿到配置信息并定义分享功能处理。 -
有些人可能会说,我直接在微信中打开要分享的链接,点击发送朋友或朋友圈不也直接可以实现分享吗?可以是可以,但样式会很丑,如下所示,只有标题+链接,苍白无力,没有样式;
而进行了权限配置,则可以实现如下自定义的分享链接,即可以定制标题+简介+图片的效果。
-
-
获取
access_token
如步骤2
获取signature流程中可知,首先要获取access_token
:String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential"; tokenUrl = tokenUrl + "&appid=" + appid + "&secret=" + secret; JSONObject tokenJson = new JSONObject(); tokenJson = getUrlResponse(tokenUrl); log.info(tokenJson.toString()); log.info("tokenJson:"+tokenJson.toString()); String token=""; try { /** * TODO:access_token应该存入缓存,设置有效期为7200s */ token = tokenJson.getString("access_token"); } catch (JSONException e) { e.printStackTrace(); log.error("报错了"); return null; }
-
获取
jsapi_ticket
String jsapiTicketUrl="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi"; JSONObject jsapiTickeJson = new JSONObject(); log.info("getJsapiTicket:获取token:"+token); if(StringUtils.isNotBlank(token)){ jsapiTicketUrl = jsapiTicketUrl.replace("ACCESS_TOKEN",token); jsapiTickeJson=getUrlResponse(jsapiTicketUrl); log.info("tokenJson:"+jsapiTickeJson.toString()); try { return (String) jsapiTickeJson.get("ticket"); } catch (JSONException e) { e.printStackTrace(); return null; } }else{ return null; }
-
获取排序
noncestr
(随机字符串)public class RandomStr { private static char ch[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1' };//最后又重复两个0和1,因为需要凑足数组长度为64 private static Random random = new Random(); //生成指定长度的随机字符串 public static String createRandomString(int length) { if (length > 0) { int index = 0; char[] temp = new char[length]; int num = random.nextInt(); for (int i = 0; i < length % 5; i++) { temp[index++] = ch[num & 63];//取后面六位,记得对应的二进制是以补码形式存在的。 num >>= 6;//63的二进制为:111111 // 为什么要右移6位?因为数组里面一共有64个有效字符。为什么要除5取余?因为一个int型要用4个字节表示,也就是32位。 } for (int i = 0; i < length / 5; i++) { num = random.nextInt(); for (int j = 0; j < 5; j++) { temp[index++] = ch[num & 63]; num >>= 6; } } return new String(temp, 0, length); } else if (length == 0) { return ""; } else { throw new IllegalArgumentException(); } } public static void main(String[] args) { System.out.println(createRandomString(16)); } }
-
通过
Sha1
加密获取signaturelong timestamp = System.currentTimeMillis() / 1000; String noncestr = RandomStr.createRandomString(16); String str = "jsapi_ticket=" + ticket + "&noncestr=" + noncestr + "×tamp=" + timestamp + "&url=" + url; String signature = Sha1.encode(str);
public class Sha1 { private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; private static String getFormattedText(byte[] bytes) { int len = bytes.length; StringBuilder buf = new StringBuilder(len * 2); // 把密文转换成十六进制的字符串形式 for (int j = 0; j < len; j++) { buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]); buf.append(HEX_DIGITS[bytes[j] & 0x0f]); } return buf.toString(); } public static String encode(String str) { if (str == null) { return null; } try { MessageDigest messageDigest = MessageDigest.getInstance("SHA1"); messageDigest.update(str.getBytes()); return getFormattedText(messageDigest.digest()); } catch (Exception e) { throw new RuntimeException(e); } } }
完成以上配置信息的生成后,后端将
JSSDK
配置信息 (携带分享页面信息的签名signature等)及其他自定义信息打包返回给前端 -
前端
JS
接口配置
因前后端不分离,所以页面还得引入
Jquery
的Js
文件<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>政策详情页面</title> </head> <body> <p class="MsoNormal" style="mso-para-margin-top: .5gd; mso-para-margin-right: 0cm; mso-para-margin-bottom: .5gd; mso-para-margin-left: 0cm; text-align: center; line-height: 150%; margin: 7.8pt 0cm 7.8pt 0cm;" align="center"><strong style="mso-bidi-font-weight: normal;"><span style="font-size: 12.0pt; line-height: 150%; font-family: '微软雅黑','sans-serif';">中共北京市委 北京市人民政府印发《关于促进中医药传承创新发展的实施方案》的通知</span></strong></p> </body> <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script> <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script> <script type="text/javascript"> $(function () { //当前页面的url地址 var currUrl = decodeURIComponent(location.href.split('#')[0]); var shareLink = window.location.href.toString();//分享链接 $.ajax({ url: "/get_wx_config", dataType : "json", data: { 'url': currUrl }, error: function (res) { console.log(res); alert("发生错误"); }, success: function (res) { console.log(res); var appId = res.appId; var nonceStr = res.nonceStr; var timestamp = res.timestamp; var signature = res.signature; //自定义返回内容 var shareImgUrl = res.backImgUrl; var backTitle = res.backTitle; var backDesc = res.backDesc; wx.config({ debug: false, //开启调试模式,开发阶段可以改成true,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: appId, //必填,公众号的唯一标识 timestamp: timestamp, // 必填,生成签名的时间戳 nonceStr: nonceStr, //必填,生成签名的随机串 signature: signature, // 必填,签名,见附录1 jsApiList: [ //必填,需要使用的JS接口列表,所有JS接口列表 见附录2 'updateAppMessageShareData', 'updateTimelineShareData' ] }); wx.ready(function () { //需在用户可能点击分享按钮前就先调用 //分享给朋友”及“分享到QQ” wx.updateAppMessageShareData({ title: '朋友我是标题', // 分享标题 desc: '朋友 我是描述', // 分享描述 link: shareLink, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致 imgUrl: shareImgUrl, // 分享图标 success: function (res) { // 设置成功 } }) //分享到朋友圈”及“分享到QQ空间 wx.updateTimelineShareData({ title: '朋友我是标题', // 分享标题 desc: '朋友 我是描述', // 分享描述 link: shareLink, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致 imgUrl: shareImgUrl, // 分享图标 success: function (res) { // 设置成功 } }) }); wx.error(function (res) { }); } }); }); </script> </html>
-
测试
打开微信开发者工具,在地址栏输入http://域名/to_detail
,点击分享,能够出现以下界面,说明已经可以实现分享了!
以上主要参考微信官方文档和结合以下两位大佬的做法:
https://www.cnblogs.com/a876459952/p/13294124.html
https://www.cnblogs.com/pxblog/p/12881454.html
三. SpringBoot+Vue前后端分离版本
-
后端变化不大,主要将
share.html
改造为Vue页面,同时加入了一个二维码扫码分享功能
点击如图所示微信图标,弹出二维码,微信扫一扫点开即可分享:
-
改造
Vue
前端页面
首先创建一个wxShare.js
// 要用到微信API function getJSSDK(url, dataForWeixin) { // 调用后台接口换取参数 axios.get('http://域名/get_wx_config', { params: { url, }, }).then((res) => { console.log(res) wx.config({ debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: res.appId, // 必填,公众号的唯一标识 timestamp: res.timestamp, // 必填,生成签名的时间戳 nonceStr: res.nonceStr, // 必填,生成签名的随机串 signature: res.signature, // 必填,签名 jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData'] // 必填,需要使用的JS接口列表 }); wx.ready(function () { //分享给朋友 wx.updateAppMessageShareData({ title: dataForWeixin.title, desc: dataForWeixin.desc, link: dataForWeixin.linkurl, imgUrl: dataForWeixin.img, success: function () { // 用户确认分享后执行的回调函数 // alert('分享成功'); }, cancel: function () { // 用户取消分享后执行的回调函数 }, fail: function (res) { alert(JSON.stringify(res)); } }); //分享到朋友圈 wx.updateTimelineShareData({ title: dataForWeixin.title, desc: dataForWeixin.desc, link: dataForWeixin.linkurl, imgUrl: dataForWeixin.img, success: function (res) { // 设置成功 // alert("分享成功!") // console.log("分享成功!") }, cancel: function () { // alert("已取消") }, fail: function (res) { alert(JSON.stringify(res)); } }) wx.error(function (res) { // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。 // alert("errorMSG:" + res); }); }); }); } export default { // 获取JSSDK getJSSDK, }
其次创建一个分享页面
wxShare.vue
,其中,title
、desc
、linkurl
、img
这四个为分享的设置,linkurl
应动态获取当前前端页面地址<template> <div> <div v-html="title"></div> <div class="wx"style="text-align: center"> <img src="../assets/wx.jpg" alt="点击分享" title="点击分享"/> </div> ...... </div> </template> <script> import share from '@/assets/js/share' import vueQr from 'vue-qr' export default { name: "wxShare", components: { vueQr }, mounted() { const url = location.href.split('#')[0]; console.log(url) const dataForWeixin = { title: '中共北京市委 北京市人民政府印发《关于促进中医药传承创新发展的实施方案》的通知', // 分享标题 desc: '为贯彻落实《中共中央、国务院关于促进中医药传承创新发展的意见》精神,结合本市实际,制定如下实施方案', // 内容描述 linkurl: window.location.href.toString(), // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致 img: 'http://wx.qlogo.cn/mmopen/ciaIftfPzwlo0coPuwwLS5Fw9UwGMlxY2ziaWpqXzevJI8dKeDvk4n3NxtZS4D8dNHSYUhbiaA6IIGnFsiagEbRlaExselicC3pEA/64', // 分享内容显示的图片(图片必须是正方形的链接) }; share.getJSSDK(url,dataForWeixin) }, methods: { }, data() { return { dialogVisible: false, shareData: { // url: 'http://cxyabc.vaiwan.com/to_detail', //需要转化成二维码的网址 url: window.location.href.toString(), //需要转化成二维码的网址 icon: require('@/assets/img.png') //二维码中间的图片,可以不设置 }, title: '<p class="MsoNormal" style="mso-para-margin-top: .5gd; mso-para-margin-right: 0cm; mso-para-margin-bottom: .5gd; mso-para-margin-left: 0cm; text-align: center; line-height: 150%; margin: 7.8pt 0cm 7.8pt 0cm;" align="center"><strong style="mso-bidi-font-weight: normal;"><span style="font-size: 12.0pt; line-height: 150%; font-family: \'微软雅黑\',\'sans-serif\';">中共北京市委北京市人民政府印发《关于促进中医药传承创新发展的实施方案》的通知</span></strong></p>\n', } } } </script>
-
将
vue
工程文件build
打包为静态文件,用nginx
做代理进行前后端分离配置
注:实际上线或开发过程可能会出现{"errMsg":"translateVoice:fail, the permission value is offline verifying"}
情况,除了百度能搜到的解决方法外,我在实际过程中遇到了以下几种解决方法:-
后端打包返回给前端的
JSSDK
配置信息格式有误,下面截图位置可以不转为String
,直接返回,因为有+@ResponseBody
注解,框架会自动返回json
对象
-
后端接收前端带域名的当前网页
url
这里,刚开始我的工程不会报错,后面一直报上面的错误,取消替换'#'
的操作,则不会报错,具体原因还在探究,至少我的项目是这样解决了报错原因的。
-
前后端分离主要结合了https://zhuanlan.zhihu.com/p/135179184
这位大佬的文章
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/171608.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...