SpringBoot JS-SDK自定義微信分享的實(shí)現(xiàn)
前言
在介紹使用微信自定義分享前,我們來(lái)先了解一下什么是自定義分享?
訪問(wèn)自定義微信外鏈地址頁(yè)面,點(diǎn)擊紅色框位置進(jìn)行分享給朋友或者朋友圈,具體操作如下圖所示:


分享后圖文消息如下圖所示:

我們要做的就是自定義下圖所示中紅框中的信息。

閑話少說(shuō),接下來(lái)就正式開(kāi)始自定義分享實(shí)戰(zhàn)環(huán)節(jié)!
自定義分享實(shí)戰(zhàn)
第一步需要先申請(qǐng)接口測(cè)試號(hào)并進(jìn)行JS接口安全域名設(shè)置
訪問(wèn)如下鏈接進(jìn)行接口測(cè)試號(hào)申請(qǐng)。點(diǎn)擊訪問(wèn) 選擇接口測(cè)試號(hào)申請(qǐng),如下圖所示:

或者直接訪問(wèn) :申請(qǐng)測(cè)試賬號(hào)頁(yè)面 如下圖所示:

點(diǎn)擊登錄進(jìn)行掃碼登錄,如下圖所示:

登錄后如下圖所示:


windows系統(tǒng)在 hosts 文件中配置回環(huán)地址的域名


第二步是下載微信web開(kāi)發(fā)者工具,可以在PC 進(jìn)行測(cè)試。
點(diǎn)擊訪問(wèn)下載頁(yè)面 如下圖所示:

傻瓜式一步一步安裝即可。
第三步 看微信操作教程并完成代碼實(shí)現(xiàn)
點(diǎn)擊訪問(wèn)微信JS-SDK說(shuō)明文檔 如下圖所示:

JSSDK使用步驟
步驟一:綁定域名(上面已經(jīng)操作了)
步驟二:引入JS文件(下面實(shí)戰(zhàn)代碼中會(huì)介紹到如何使用)

步驟三:通過(guò)config接口注入權(quán)限驗(yàn)證配置(下面實(shí)戰(zhàn)代碼中會(huì)介紹到如何使用)

步驟四:通過(guò)ready接口處理成功驗(yàn)證(這里就不詳細(xì)介紹了具體內(nèi)容請(qǐng)參看微信文檔查看)
步驟五:通過(guò)error接口處理失敗驗(yàn)證(這里就不詳細(xì)介紹了具體內(nèi)容請(qǐng)參看微信文檔查看)
上面步驟步驟三中的 signature是一個(gè)重要的參數(shù),生成它需要獲取 jsapi_ticket,而生成 jsapi_ticket 需要通過(guò) access_token。
獲取signature流程如下:
- 獲取 access_token 然后根據(jù) access_token 獲取 jsapi_ticket 。
- 排序 noncestr(隨機(jī)字符串), 有效的jsapi_ticket, timestamp(時(shí)間戳),url(當(dāng)前網(wǎng)頁(yè)的URL,不包含#及其后面部分)4個(gè)參數(shù)拼接例如:noncestr=XX&jsapi_ticket=XX&jtimestamp=XX&jurl=XX
- 然后通過(guò)sha1加密拼接的4個(gè)參數(shù)獲取到signature
可能你對(duì)操作流程還是看不懂,沒(méi)有關(guān)系可以直接參考代碼實(shí)現(xiàn),接下來(lái)就是代碼實(shí)現(xiàn):
初始化微信JSSDK配置信息 Controller 內(nèi)容如下:
@RestController
@RequestMapping("/weixin")
public class WeiXinDemoController {
@Autowired
private WeiXinService weiXinService;
/**
* 初始化微信JSSDK配置信息
* @param request
* @param response
* @return
* @throws Exception
*/
@RequestMapping("/initWXJSSDKConfigInfo")
public String initWXJSConfig (HttpServletRequest request,HttpServletResponse response) throws Exception{
String shareUrl = request.getParameter("shareUrl");//分享的URL
Map map = weiXinService.initJSSDKConfigInfo(shareUrl);
String json = weiXinService.mapToJson(map);
return json;
}
}
初始化JSSDK配置信息,配置信息有:noncestr(隨機(jī)字符串)、有效的jsapi_ticket、timestamp(時(shí)間戳)、shareUrl(當(dāng)前網(wǎng)頁(yè)的URL,不包含#及其后面部分)appid(公眾號(hào) appid)。
/**
* 初始化JSSDK配置信息
* @param shareUrl
* @return
* @throws Exception
*/
public Map initJSSDKConfigInfo(String shareUrl) throws Exception {
String accessToken = this.getJSSDKAccessToken();
String jsapiTicket = this.getJSSDKJsapiTicket(accessToken);
String timestamp = Long.toString(System.currentTimeMillis() / 1000);
String nonceStr = UUID.randomUUID().toString();
String signature = this.buildJSSDKSignature(jsapiTicket,timestamp,nonceStr,shareUrl);
Map<String,String> map = new HashMap<String,String>();
map.put("shareUrl", shareUrl);
map.put("jsapi_ticket", jsapiTicket);
map.put("nonceStr", nonceStr);
map.put("timestamp", timestamp);
map.put("signature", signature);
map.put("appid", weiXinConfig.getAppID());
return map;
}
獲取 JSSDK access_token 方法。
public String getJSSDKAccessToken() {
String token = null;
String url = JSSDK_ACCESSTOKEN.replaceAll("APPID",
weiXinConfig.getAppID()).replaceAll("APPSECRET",
weiXinConfig.getAppsecret());
String json = postRequestForWeiXinService(url);
Map map = jsonToMap(json);
if (map != null) {
token = (String) map.get("access_token");
}
return token;
}
獲取 JSSDK jsapi_ticket 方法。
public String getJSSDKJsapiTicket(String token) {
String url = JSSDK_GETTICKET.replaceAll("ACCESS_TOKEN", token);
String json = postRequestForWeiXinService(url);
Map map = jsonToMap(json);
String jsapi_ticket = null;
if (map != null) {
jsapi_ticket = (String) map.get("ticket");
}
return jsapi_ticket;
}
拼接 noncestr(隨機(jī)字符串), 有效的jsapi_ticket、 timestamp(時(shí)間戳)、url(當(dāng)前網(wǎng)頁(yè)的URL,不包含#及其后面部分)并通過(guò)sha1進(jìn)行加密。
/**
* 構(gòu)建分享鏈接的簽名。
* @param ticket
* @param nonceStr
* @param timeStamp
* @param url
* @return
* @throws Exception
*/
public static String buildJSSDKSignature(String ticket,String timestamp,String nonceStr ,String url) throws Exception {
String orderedString = "jsapi_ticket=" + ticket
+ "&noncestr=" + nonceStr + "×tamp=" + timestamp
+ "&url=" + url;
return sha1(orderedString);
}
/**
* sha1 加密JSSDK微信配置參數(shù)獲取簽名。
*
* @param signature
* @param timestamp
* @param nonce
* @return
*/
public static String sha1(String orderedString) throws Exception {
String ciphertext = null;
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] digest = md.digest(orderedString.getBytes());
ciphertext = byteToStr(digest);
return ciphertext.toLowerCase();
}
/**
* 將字節(jié)數(shù)組轉(zhuǎn)換為十六進(jìn)制字符串
*
* @param byteArray
* @return
*/
private static String byteToStr(byte[] byteArray) {
String strDigest = "";
for (int i = 0; i < byteArray.length; i++) {
strDigest += byteToHexStr(byteArray[i]);
}
return strDigest;
}
/**
* 將字節(jié)轉(zhuǎn)換為十六進(jìn)制字符串
*
* @param mByte
* @return
*/
private static String byteToHexStr(byte mByte) {
char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
char[] tempArr = new char[2];
tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
tempArr[1] = Digit[mByte & 0X0F];
String s = new String(tempArr);
return s;
}
基礎(chǔ)工具方法如下:
public String mapToJson(Map map){
Gson gson = new Gson();
String json = gson.toJson(map);
return json;
}
private Map jsonToMap(String json) {
Gson gons = new Gson();
Map map = gons.fromJson(json, new TypeToken<Map>(){}.getType());
return map;
}
private String postRequestForWeiXinService(String getAccessTokenUrl) {
ResponseEntity<String> postForEntity = restTemplate.postForEntity(getAccessTokenUrl, null, String.class);
String json = postForEntity.getBody();
return json;
}
private String getRequestForWeiXinService(String getUserInfoUrl) {
ResponseEntity<String> postForEntity = restTemplate.getForEntity(getUserInfoUrl.toString(), String.class);
String json = postForEntity.getBody();
return json;
}
wxShare.js 主要是獲取JSSDK配置信息并定義分享功能處理。具體代碼如下:
//alert(window.location.href.split('#')[0]);/***用于獲得當(dāng)前連接url用**/
/***用戶點(diǎn)擊分享到微信圈后加載接口接口*******/
$.post("/weixin/initWXJSSDKConfigInfo",{"shareUrl":window.location.href.split('#')[0]},function(data,status){
data=eval("("+data+")");
wx.config({
debug: false,
appId: data.appid,
timestamp:data.timestamp,
nonceStr:data.nonceStr,
signature:data.signature,
jsApiList: [
'checkJsApi',
'onMenuShareTimeline',
'onMenuShareAppMessage',
'onMenuShareQQ',
'onMenuShareWeibo',
'onMenuShareQZone',
'hideOptionMenu',
]
});
var shareTitle = $("#wx_share_span").data("shareTitle");
if(!shareTitle){
shareTitle = $("title").html();
}
var shareImg = $("#wx_share_span").data("shareImg");
if(!shareImg){
//shareImg = common.bp()+'/m_images/shareImg.jpg';
}
var shareLink = $("#wx_share_span").data("shareLink");
if(!shareLink){
shareLink = window.location.href.split('#')[0];
}
var shareDesc = $("#wx_share_span").data("shareDesc");
if(!shareDesc){
shareDesc = $("meta[name=description]").attr("content");
}
wx.ready(function(){
// alert("準(zhǔn)備分享");
wx.onMenuShareTimeline({
title : shareTitle, // 分享標(biāo)題
link : shareLink, // 分享鏈接
imgUrl : shareImg, // 分享圖標(biāo)
success : function() {
// 用戶確認(rèn)分享后執(zhí)行的回調(diào)函數(shù)
//alert("分享成功");
},
cancel : function() {
// 用戶取消分享后執(zhí)行的回調(diào)函數(shù)
//alert("分享取消");
}
});
//wx.hideOptionMenu();/***隱藏分享菜單****/
wx.onMenuShareAppMessage({
title: shareTitle, // 分享標(biāo)題
desc: shareDesc, // 分享描述
link: shareLink, // 分享鏈接,該鏈接域名或路徑必須與當(dāng)前頁(yè)面對(duì)應(yīng)的公眾號(hào)JS安全域名一致
imgUrl: shareImg, // 分享圖標(biāo)
success: function () {
// 用戶確認(rèn)分享后執(zhí)行的回調(diào)函數(shù)
},
cancel: function () {
// 用戶取消分享后執(zhí)行的回調(diào)函數(shù)
}
});
wx.onMenuShareQQ({
title: shareTitle, // 分享標(biāo)題
desc: shareDesc, // 分享描述
link: shareLink, // 分享鏈接
imgUrl: shareImg, // 分享圖標(biāo)
success: function () {
// 用戶確認(rèn)分享后執(zhí)行的回調(diào)函數(shù)
},
cancel: function () {
// 用戶取消分享后執(zhí)行的回調(diào)函數(shù)
}
});
wx.onMenuShareWeibo({
title: shareTitle, // 分享標(biāo)題
desc: shareDesc, // 分享描述
link: shareLink, // 分享鏈接
imgUrl: shareImg, // 分享圖標(biāo)
success: function () {
// 用戶確認(rèn)分享后執(zhí)行的回調(diào)函數(shù)
},
cancel: function () {
// 用戶取消分享后執(zhí)行的回調(diào)函數(shù)
}
});
wx.onMenuShareQZone({
title: shareTitle, // 分享標(biāo)題
desc: shareDesc, // 分享描述
link: shareLink, // 分享鏈接
imgUrl: shareImg, // 分享圖標(biāo)
success: function () {
// 用戶確認(rèn)分享后執(zhí)行的回調(diào)函數(shù)
},
cancel: function () {
// 用戶取消分享后執(zhí)行的回調(diào)函數(shù)
}
});
});
});
分享頁(yè)面該頁(yè)面需要引入wxShare.js和jweixin-1.2.0.js,并且通過(guò)在隱藏的span標(biāo)簽上定義自定義分享的內(nèi)容,具體代碼如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="/jquery-1.8.3.min.js" type="text/javascript" ></script>
</head>
<body>
<span id="wx_share_span" style="display: none"></span>
<script type="text/javascript">
$(document).ready(function(){
$("#wx_share_span").data("shareTitle", "桌前明月教你玩微信公眾號(hào)自定義分享");
$("#wx_share_span").data("shareDesc", "保證學(xué)會(huì)哈!");
//$("#wx_share_span").data("shareLink", "/weixinshare.html");
//$("#wx_share_span").data("shareImg", "/banner.jpg");
});
</script>
<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
<script type="text/javascript" src="/wxShare.js"></script>
</body>
</html>
測(cè)試
訪問(wèn):http://www.zhuoqianmingyue.com:8090/weixinshare.html 未引入 wxShare.js 的測(cè)試結(jié)果如下:

引入 wxShare.js 的測(cè)試結(jié)果如下:

一般情況下我們通過(guò)接口測(cè)試號(hào)配置成測(cè)試環(huán)境域名,上述測(cè)試通過(guò)后就可以在正式服務(wù)號(hào)上配置JS接口安全域名,順便在把我們項(xiàng)目配置的 appid 換成服務(wù)號(hào)的 appid 即可。具體操作如下:


小結(jié)
微信自定義分享具體操作步驟如下:
- 定義獲取JS-SDK配置信息接口
- 定義頁(yè)面初始化調(diào)用JS-SDK配置信息接口 js 代碼和定義分享接口js代碼
- 分享頁(yè)面引入 jweixin-1.2.0.js和 調(diào)用JS-SDK配置信息的js文件
三步中最為總要的就是第一步:定義獲取JS-SDK配置信息接口,這個(gè)接口需要獲取jsapi_ticket 并通過(guò)和配置信息參數(shù)一起生成簽名 signature。
在這里再三強(qiáng)調(diào)一下,微信提供操作文檔一定要多看幾篇,因?yàn)楹芏嗉?xì)節(jié)都在文檔中進(jìn)行了說(shuō)明。當(dāng)你把微信提供操作文檔看透,你就會(huì)覺(jué)得其實(shí)就是個(gè)API 調(diào)用而已。
代碼示例
具體代碼示例請(qǐng)查看我的GitHub 倉(cāng)庫(kù) springbootexamples 中的 spring-boot-2.x-weixin 查看。
GitHub:https://github.com/zhuoqianmingyue/springbootexamples
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java使用Collections工具類(lèi)對(duì)List集合進(jìn)行排序
這篇文章主要介紹了Java使用Collections工具類(lèi)對(duì)List集合進(jìn)行排序,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10
SpringBoot升級(jí)3.2報(bào)錯(cuò)Invalid value type for
這篇文章給大家介紹了SpringBoot升級(jí)3.2報(bào)錯(cuò)Invalid value type for attribute ‘factoryBeanObjectType‘: java.lang.String的解決方案,文中有詳細(xì)的原因分析,需要的朋友可以參考下2023-12-12
Java實(shí)現(xiàn)房屋出租系統(tǒng)詳解
這篇文章主要介紹了實(shí)現(xiàn)Java房屋出租系統(tǒng)的實(shí)現(xiàn)過(guò)程,文章條理清晰,在實(shí)現(xiàn)過(guò)程中加深了對(duì)相關(guān)概念的理解,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10
Spring學(xué)習(xí)之開(kāi)發(fā)環(huán)境搭建的詳細(xì)步驟
本篇文章主要介紹了Spring學(xué)習(xí)之開(kāi)發(fā)環(huán)境搭建的詳細(xì)步驟,具有一定的參考價(jià)值,有興趣的可以了解一下2017-07-07
Java HashSet集合存儲(chǔ)遍歷學(xué)生對(duì)象代碼實(shí)例
這篇文章主要介紹了Java HashSet集合存儲(chǔ)遍歷學(xué)生對(duì)象代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
SpringCloud之熔斷監(jiān)控Hystrix Dashboard的實(shí)現(xiàn)
這篇文章主要介紹了SpringCloud之熔斷監(jiān)控Hystrix Dashboard的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09

