微信公众号-自定义微信分享(vue)(JS-SDK)
💖1.需求描述
日常公众号开发中,业务部门对于微信内置分享(右上角->分享到朋友等)效果不太满意,需要我们自定义相关分享效果
🌟1.1微信默认分享效果展示
🌟1.2通过自定义分享后效果展示
🌟1.3微信官方文档
JS-SDK说明文档:
https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html
📖2.具体实现
🌟2.1后端(这里只展示大概代码,具体实现根据自己业务为准)
⭐2.1.1Controller层
@RequestMapping("/getSignature")
private MsgData getSignature(String url, HttpServletResponse response, HttpServletRequest request) throws Exception {
MsgData msg = MsgData.successMsg();
String jsapi_ticket = wechatUtil.getJsapiTicket();if (jsapi_ticket == null || jsapi_ticket == "") {
msg.fail("失败");
return msg;
}
String nonceStr = UUID.randomUUID().toString();
String timestamp = Long.toString(System.currentTimeMillis() / 1000);
String str = "";
String signature = "";
str += "jsapi_ticket=" + jsapi_ticket;
str += "&noncestr=" + nonceStr;
str += "×tamp=" + timestamp;
str += "&url=" + url;
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(str.getBytes("UTF-8"));
signature = byteToHex(crypt.digest());
Map<String, String> ret = new HashMap<String, String>();
ret.put("url", url);
ret.put("jsapi_ticket", jsapi_ticket);
ret.put("nonceStr", nonceStr);
ret.put("timestamp", timestamp);
ret.put("signature", signature);
ret.put("appId", WechatConstant.APP_ID);
msg.setData(ret);
return msg;
}
private String byteToHex(final byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash) {
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
⭐2.1.2工具类wechatUtil
public String getJsapiTicket() {
if (redisService.hasKey(WechatConstant.JSAPI_TICKET_REDIS)) {
return (String) redisService.get(WechatConstant.JSAPI_TICKET_REDIS);
}
return getServerJsapiTicket();
}
private synchronized String getServerJsapiTicket() {
try {
if (redisService.hasKey(WechatConstant.JSAPI_TICKET_REDIS)) {
return (String) redisService.get(WechatConstant.JSAPI_TICKET_REDIS);
}
String accessToken = getAccessToken();
if (accessToken == null || accessToken == "") {
return null;
} else {
String jsurl = WechatConstant.JSAPI_TICKET_URL;
String url = String.format(jsurl, accessToken);
String strTicket = ConnectionUtil.getUrlResult(url, null, "GET");
if (StringUtils.isBlank(strTicket)) {
return null;
}
JSONObject json = JSONObject.parseObject(strTicket);
if (json.containsKey("ticket")) {
String ticket = json.getString("ticket");
redisService.set(WechatConstant.JSAPI_TICKET_REDIS, ticket);
redisService.expire(WechatConstant.JSAPI_TICKET_REDIS, 60 * 110);// 110分钟过期
return ticket;
}
}
} catch (Exception e) {
logger.error("JsapiTicket-错误", e);
}
return null;
}
⭐2.1.3工具类ConnectionUtil(HTTP接口工具,可根据项目自行封装)
public static String getUrlResult(String uri, String data, String method) {
StringBuffer sbf = new StringBuffer();
BufferedReader reader = null;
HttpURLConnection connection = null;
try {
URL url = new URL(uri);
connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestMethod(method);
connection.setConnectTimeout(8 * 1000);
connection.setReadTimeout(8 * 1000);
connection.setUseCaches(false);
connection.setInstanceFollowRedirects(true);
connection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded; charset=UTF-8");
if (data != null && data.trim().length() != 0) {
OutputStream outwritestream = null;
try {
byte[] writebytes = data.getBytes();
// 设置文件长度
connection.setRequestProperty("Content-Length",
String.valueOf(writebytes.length));
outwritestream = connection.getOutputStream();
outwritestream.write(data.getBytes("UTF-8"));
outwritestream.flush();
} catch (Exception e) {
logger.error(e.getMessage());
} finally {
try {
outwritestream.close();
} catch (Exception e) {
}
}
}
connection.connect();
reader = new BufferedReader(
new InputStreamReader(connection.getInputStream(), "UTF-8"));
String lines;
while ((lines = reader.readLine()) != null) {
sbf.append(lines);
}
} catch (Exception e) {
logger.error(e.getMessage());
} finally {
try {
reader.close();
} catch (IOException e) {
logger.error(e.getMessage());
}
try {
connection.disconnect();
} catch (Exception e) {
logger.error(e.getMessage());
}
}
return sbf.toString();
}
注意:
由于微信获取api_ticket接口次数有限,建议将【api_ticket 】存储在本地缓存服务器中(这里使用的是redis)
🌟2.2前端(vue)
⭐2.2.1封装公共工具方法
/**
* 配置微信js-sdk
* @param {Object} shareData
* link:路径
* title:标题
* desc:描述
* imgUrl:图片链接
*/
const wxJsSdkConfig = function(shareData) { //配置微信js-sdk
let url = window.location.href.split('#')[0];
if (url != null && url != "") {
tcmAxios({
method: 'post',
url: requestUrl.getSignature,
data: {
url: url
},
then: function(response) {
if (response.success) {
let data = response.data;
let appId = data.appId;
let timestamp = Number(data.timestamp);
let nonceStr = data.nonceStr;
let signature = data.signature;
let jsApiList = ["updateAppMessageShareData",
"updateTimelineShareData"
];
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: appId, // 必填,公众号的唯一标识
timestamp: timestamp, // 必填,生成签名的时间戳
nonceStr: nonceStr, // 必填,生成签名的随机串
signature: signature, // 必填,签名
jsApiList: jsApiList // 必填,需要使用的JS接口列表
});
wx.ready(function() { //需在用户可能点击分享按钮前就先调用
wx.updateAppMessageShareData({
title: shareData.title, // 分享标题
desc: shareData.desc, // 分享描述
link: shareData.link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: shareData.imgUrl, // 分享图标
success: function() {
}
});
wx.updateTimelineShareData({
title: shareData.title, // 分享标题
link: shareData.link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: shareData.imgUrl, // 分享图标
success: function() {
// 设置成功
}
})
});
}
},
});
}
}
⭐2.2.2使用
let shareData = {
link:window.location.href,
title:"标题",
desc:"描述",
imgUrl:"图片链接",
};
wxJsSdkConfig(shareData);
注意:
在用户点击分享之前调用