SpringBoot JS-SDK自定义微信分享的实现

作者:桌前明月 时间:2023-11-10 05:08:28 

前言

在介绍使用微信自定义分享前,我们来先了解一下什么是自定义分享?

访问自定义微信外链地址页面,点击红色框位置进行分享给朋友或者朋友圈,具体操作如下图所示:

SpringBoot JS-SDK自定义微信分享的实现

SpringBoot JS-SDK自定义微信分享的实现
分享后图文消息如下图所示:
SpringBoot JS-SDK自定义微信分享的实现

我们要做的就是自定义下图所示中红框中的信息。

SpringBoot JS-SDK自定义微信分享的实现

闲话少说,接下来就正式开始自定义分享实战环节!

自定义分享实战

第一步需要先申请接口测试号并进行JS接口安全域名设置

访问如下链接进行接口测试号申请。点击访问 选择接口测试号申请,如下图所示:

SpringBoot JS-SDK自定义微信分享的实现

或者直接访问 :申请测试账号页面 如下图所示:

SpringBoot JS-SDK自定义微信分享的实现

点击登录进行扫码登录,如下图所示:

SpringBoot JS-SDK自定义微信分享的实现

登录后如下图所示:

SpringBoot JS-SDK自定义微信分享的实现

SpringBoot JS-SDK自定义微信分享的实现

windows系统在 hosts 文件中配置回环地址的域名

SpringBoot JS-SDK自定义微信分享的实现

SpringBoot JS-SDK自定义微信分享的实现

第二步是下载微信web开发者工具,可以在PC 进行测试。

点击访问下载页面 如下图所示:

SpringBoot JS-SDK自定义微信分享的实现

傻瓜式一步一步安装即可。

第三步 看微信操作教程并完成代码实现

点击访问微信JS-SDK说明文档 如下图所示:

SpringBoot JS-SDK自定义微信分享的实现

JSSDK使用步骤

步骤一:绑定域名(上面已经操作了)

步骤二:引入JS文件(下面实战代码中会介绍到如何使用)

SpringBoot JS-SDK自定义微信分享的实现
步骤三:通过config接口注入权限验证配置(下面实战代码中会介绍到如何使用)
SpringBoot JS-SDK自定义微信分享的实现

步骤四:通过ready接口处理成功验证(这里就不详细介绍了具体内容请参看微信文档查看)

步骤五:通过error接口处理失败验证(这里就不详细介绍了具体内容请参看微信文档查看)

上面步骤步骤三中的 signature是一个重要的参数,生成它需要获取 jsapi_ticket,而生成 jsapi_ticket 需要通过 access_token

获取signature流程如下:

  1. 获取 access_token 然后根据 access_token 获取 jsapi_ticket 。

  2. 排序 noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳),url(当前网页的URL,不包含#及其后面部分)4个参数拼接例如:noncestr=XX&jsapi_ticket=XX&jtimestamp=XX&jurl=XX

  3. 然后通过sha1加密拼接的4个参数获取到signature

可能你对操作流程还是看不懂,没有关系可以直接参考代码实现,接下来就是代码实现:

初始化微信JSSDK配置信息 Controller 内容如下:


@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(随机字符串)、有效的jsapi_ticket、timestamp(时间戳)、shareUrl(当前网页的URL,不包含#及其后面部分)appid(公众号 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(随机字符串), 有效的jsapi_ticket、 timestamp(时间戳)、url(当前网页的URL,不包含#及其后面部分)并通过sha1进行加密。


/**
  * 构建分享链接的签名。
  * @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 + "&timestamp=" + timestamp
       + "&url=" + url;
   return sha1(orderedString);
 }
  /**
  * sha1 加密JSSDK微信配置参数获取签名。
  *
  * @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();
 }
 /**
  * 将字节数组转换为十六进制字符串
  *
  * @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;
 }
 /**
  * 将字节转换为十六进制字符串
  *
  * @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;
 }

基础工具方法如下:


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]);/***用于获得当前连接url用**/
/***用户点击分享到微信圈后加载接口接口*******/
$.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("准备分享");
   wx.onMenuShareTimeline({
     title : shareTitle, // 分享标题
     link : shareLink, // 分享链接
     imgUrl : shareImg, // 分享图标
     success : function() {
       // 用户确认分享后执行的回调函数
       //alert("分享成功");
     },
     cancel : function() {
       // 用户取消分享后执行的回调函数
       //alert("分享取消");
     }
   });
   //wx.hideOptionMenu();/***隐藏分享菜单****/
   wx.onMenuShareAppMessage({
   title: shareTitle, // 分享标题
   desc: shareDesc, // 分享描述
   link: shareLink, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
   imgUrl: shareImg, // 分享图标
   success: function () {
   // 用户确认分享后执行的回调函数
   },
   cancel: function () {
   // 用户取消分享后执行的回调函数
   }
 });
   wx.onMenuShareQQ({
   title: shareTitle, // 分享标题
   desc: shareDesc, // 分享描述
   link: shareLink, // 分享链接
   imgUrl: shareImg, // 分享图标
   success: function () {
   // 用户确认分享后执行的回调函数
   },
   cancel: function () {
   // 用户取消分享后执行的回调函数
   }
 });
   wx.onMenuShareWeibo({
   title: shareTitle, // 分享标题
   desc: shareDesc, // 分享描述
   link: shareLink, // 分享链接
   imgUrl: shareImg, // 分享图标
   success: function () {
   // 用户确认分享后执行的回调函数
   },
   cancel: function () {
   // 用户取消分享后执行的回调函数
   }
 });
   wx.onMenuShareQZone({
   title: shareTitle, // 分享标题
   desc: shareDesc, // 分享描述
   link: shareLink, // 分享链接
   imgUrl: shareImg, // 分享图标
   success: function () {
   // 用户确认分享后执行的回调函数
   },
   cancel: function () {
   // 用户取消分享后执行的回调函数
   }
 });
 });
});

分享页面该页面需要引入wxShare.js和jweixin-1.2.0.js,并且通过在隐藏的span标签上定义自定义分享的内容,具体代码如下:


<!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", "桌前明月教你玩微信公众号自定义分享");
$("#wx_share_span").data("shareDesc", "保证学会哈!");
//$("#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>

测试

访问:http://www.zhuoqianmingyue.com:8090/weixinshare.html 未引入 wxShare.js 的测试结果如下:

SpringBoot JS-SDK自定义微信分享的实现

引入 wxShare.js 的测试结果如下:

SpringBoot JS-SDK自定义微信分享的实现

一般情况下我们通过接口测试号配置成测试环境域名,上述测试通过后就可以在正式服务号上配置JS接口安全域名,顺便在把我们项目配置的 appid 换成服务号的 appid 即可。具体操作如下:

SpringBoot JS-SDK自定义微信分享的实现

SpringBoot JS-SDK自定义微信分享的实现

小结

微信自定义分享具体操作步骤如下:

  • 定义获取JS-SDK配置信息接口

  • 定义页面初始化调用JS-SDK配置信息接口 js 代码和定义分享接口js代码

  • 分享页面引入 jweixin-1.2.0.js和 调用JS-SDK配置信息的js文件

三步中最为总要的就是第一步:定义获取JS-SDK配置信息接口,这个接口需要获取jsapi_ticket 并通过和配置信息参数一起生成签名 signature。

在这里再三强调一下,微信提供操作文档一定要多看几篇,因为很多细节都在文档中进行了说明。当你把微信提供操作文档看透,你就会觉得其实就是个API 调用而已。

代码示例

具体代码示例请查看我的GitHub 仓库 springbootexamples 中的 spring-boot-2.x-weixin 查看。

GitHub:https://github.com/zhuoqianmingyue/springbootexamples

来源:https://blog.csdn.net/ljk126wy/article/details/100714362

标签:SpringBoot,JS-SDK,微信分享
0
投稿

猜你喜欢

  • 如何使用Flutter发布安卓应用

    2022-09-07 08:46:07
  • Java实现显示指定类型的文件

    2021-10-26 11:30:37
  • java 如何读取properties文件

    2023-08-28 05:23:01
  • JAVA实现心跳检测(长连接)

    2022-12-16 04:26:30
  • springboot整合spring-retry的实现示例

    2022-01-13 01:25:53
  • Java模拟实现斗地主发牌

    2022-07-09 02:16:52
  • SpringBoot使用Redis实现分布式锁

    2021-11-06 20:10:22
  • obix协议在java中的配置和使用详解

    2023-11-25 20:59:42
  • Android View事件机制 21问21答

    2022-10-14 04:27:10
  • Android使用 Coroutine + Retrofit打造简单的HTTP请求库

    2023-11-17 04:56:11
  • 新手初学Java数组

    2023-12-01 11:18:40
  • Unity代码实现序列帧动画播放器

    2023-03-24 23:48:45
  • bool当成函数参数错误理解

    2021-07-30 09:27:18
  • 关于SpringCloud的微服务结构及微服务远程调用

    2021-11-06 20:11:45
  • c#和javascript函数相互调用示例分享

    2023-10-08 21:33:52
  • Android实现随手指移动小球

    2021-06-03 23:38:46
  • Java由浅入深讲解继承下

    2023-11-25 12:21:26
  • C#表达式树Expression动态创建表达式

    2023-03-26 06:44:39
  • C#中Dictionary<TKey,TValue>排序方式的实现

    2021-07-13 10:59:10
  • java设计模式之工厂方法模式

    2022-08-29 05:14:10
  • asp之家 软件编程 m.aspxhome.com