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.2工具类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);
注意:
- 在用户点击分享之间调用