先说句题外话:微信已经不支持自定义按钮调用微信分享了,只能自定义分享内容,然后使用官方的按钮来进行分享操作,。。。
微信分享接口开发核心使用的是微信的js-sdk,下面是官网文档上的使用步骤
1.1 JSSDK使用步骤
1.1.1 步骤一:绑定域名
1.1.2 步骤二:引入JS文件
1.1.3 步骤三:通过config接口注入权限验证配置
1.1.4 步骤四:通过ready接口处理成功验证
1.1.5 步骤五:通过error接口处理失败验证
其中绑定域名和引入js文件都没什么好说的,安装官方文档来即可。
关键的是第三步:通过config接口注入权限验证配置。官网上对于这一步骤讲述的十分简单,我在这里详细阐述一番。
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,生成签名的随机串
signature: '',// 必填,签名,见附录1
jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
对于上述参数,appId我就不用讲了,从微信公众号后台上可以拿到。timestamp和nonceStr是我们自己生成的,也很简单。唯一麻烦得是
signature签名的生成。
生成signature需要两个步骤,下面是这两个步骤
1、我们需要从微信获取
jsapi_ticket
jsapi_ticket是公众号用于调用微信JS接口的临时票据,需要通过access_token来获取。
注:
jsapi_ticket 和
access_token有效时间都为7200秒,即两个小时。。需要服务器存储且定时刷新的。。如有不懂,可参看我的这篇博客。 spring通过定时任务存储并定时刷新access_token、jsapi_ticket
2、
对于生成的
j
sapi_ticket ,我们需要和
timestamp、
nonceStr和当前页面的url通过签名算法生成
signature
现在我们来一一讲述上面的两个步骤,首先,第一步获取jsapi_ticket
代码如下:
//此处的token指的是access_token public static String getJsApiTicket(String token) throws Exception{ if(token==null||token=="") { return ""; } String url="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+token+"&type=jsapi"; String result= HttpsRequestUtil.doGet(url); ObjectMapper mapper=new ObjectMapper(); JsonNode node = mapper.readTree(result); return node.get("ticket").textValue(); }
什么??不知道access_token怎么获取???好吧,我顺便讲一下。
public static String initToken() throws Exception{ String tokenUrl="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+APPID+"&secret="+SECRET; String result=HttpsRequestUtil.doGet(tokenUrl); ObjectMapper mapper=new ObjectMapper(); return mapper.readTree(result).get("access_token").textValue(); }
顺便给一下核心类
HttpsRequestUtil和依赖类
MyX509TrustManager。。这两个类的核心代码是从网上百度来的,,感谢贡献的大神!!
代码见下:
package com.wx.jlyc.wx.util; import javax.net.ssl.X509TrustManager; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; /** * @Author: Yun * @Description: 证书信任管理器,为了能够发送https请求 * @Date: Created in 2017-11-29 14:51 */ public class MyX509TrustManager implements X509TrustManager { // 检查客户端证书 public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } // 检查服务器端证书 public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } // 返回受信任的X509证书数组 public X509Certificate[] getAcceptedIssuers() { return null; } }
package com.wx.jlyc.wx.util; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import java.io.*; import java.net.URL; /** * @Author: Yun * @Description: HTTPS请求工具 * @Date: Created in 2017-12-26 16:03 */ public class HttpsRequestUtil { /** * 发送get请求 * @param href 请求的url * @return */ public static String doGet(String href) { //建立连接 URL url; HttpsURLConnection httpUrlConn=null; InputStream inputStream=null; BufferedReader bufferedReader=null; InputStreamReader inputStreamReader=null; try { url = new URL(href); httpUrlConn = (HttpsURLConnection) url.openConnection(); // 创建SSLContext对象,并使用我们指定的信任管理器初始化 TrustManager[] tm = { new MyX509TrustManager() }; SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); sslContext.init(null, tm, new java.security.SecureRandom()); // 从上述SSLContext对象中得到SSLSocketFactory对象 SSLSocketFactory ssf = sslContext.getSocketFactory(); httpUrlConn.setSSLSocketFactory(ssf); httpUrlConn.setDoOutput(true); httpUrlConn.setDoInput(true); // 设置请求方式(GET/POST) httpUrlConn.setRequestMethod("GET"); // 取得输入流 inputStream = httpUrlConn.getInputStream(); inputStreamReader = new InputStreamReader(inputStream, "utf-8"); bufferedReader = new BufferedReader(inputStreamReader); //读取响应内容 StringBuffer buffer = new StringBuffer(); String str; while ((str = bufferedReader.readLine()) != null) { buffer.append(str); } return buffer.toString(); } catch (Exception e) { e.printStackTrace(); }finally { try { bufferedReader.close(); } catch (IOException e) { e.printStackTrace(); } try { inputStreamReader.close(); } catch (IOException e) { e.printStackTrace(); } // 释放资源 try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } httpUrlConn.disconnect(); } return null; } /** * 发送post请求 * @param href 请求的url * @param json 请求的参数(json格式) * @return */ public static String doPost(String href,String json){ URL url; HttpsURLConnection httpUrlConn=null; InputStream inputStream=null; BufferedReader bufferedReader=null; InputStreamReader inputStreamReader=null; try { url = new URL(href); httpUrlConn = (HttpsURLConnection) url.openConnection(); // 创建SSLContext对象,并使用我们指定的信任管理器初始化 TrustManager[] tm = { new MyX509TrustManager() }; SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); sslContext.init(null, tm, new java.security.SecureRandom()); // 从上述SSLContext对象中得到SSLSocketFactory对象 SSLSocketFactory ssf = sslContext.getSocketFactory(); httpUrlConn.setSSLSocketFactory(ssf); httpUrlConn.setDoOutput(true); httpUrlConn.setDoInput(true); httpUrlConn.setUseCaches(false); // 设置请求方式(GET/POST) httpUrlConn.setRequestMethod("POST"); //将menu数据作为请求参数 OutputStream outputStream = httpUrlConn.getOutputStream(); // 注意编码格式,防止中文乱码 outputStream.write(json.getBytes("UTF-8")); outputStream.close(); // 取得输入流 inputStream = httpUrlConn.getInputStream(); inputStreamReader = new InputStreamReader(inputStream, "utf-8"); bufferedReader = new BufferedReader(inputStreamReader); //读取响应内容 StringBuffer buffer = new StringBuffer(); String str; while ((str = bufferedReader.readLine()) != null) { buffer.append(str); } return buffer.toString(); } catch (Exception e) { e.printStackTrace(); }finally { try { bufferedReader.close(); } catch (IOException e) { e.printStackTrace(); } try { inputStreamReader.close(); } catch (IOException e) { e.printStackTrace(); } // 释放资源 try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } httpUrlConn.disconnect(); } return null; } }
这样一来,微信的jsapi_ticket我们已经获取到了。。接下来就是将各个参数通过签名算法生成
signature签名了。
代码见下:
/** * 获取微信的js config接口需要的参数 * @param url 页面的url * @return * @throws Exception */ @PostMapping("/config") @ResponseBody public Msg getWxJsConfig(String url) throws Exception { WxToken wx_token=tokenService.getToken(); //生成随机串 String nonceStr = UUID.randomUUID().toString().replace("-", "").substring(0, 16); //生成时间戳 String timestamp = String.valueOf(System.currentTimeMillis() / 1000); //使用url键值对的方式拼接字符串 String str = "jsapi_ticket="+wx_token.getJsapiTicket()+"&noncestr="+nonceStr+"×tamp="+timestamp+"&url="+url; //对字符串进行SHA-1方式加密 MessageDigest md = MessageDigest.getInstance("SHA-1"); byte[] digest = md.digest(str.getBytes()); String signature = byteToStr(digest); return Msg.success().add("appId", TokenUtils.APPID).add("timestamp", timestamp).add("nonceStr", nonceStr).add("signature", signature); } private static String byteToStr(byte[] byteArray) { String strDigest = ""; for (int i = 0; i < byteArray.length; i++) { strDigest += byteToHexStr(byteArray[i]); } return strDigest; } 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; }
安装上述做法,我们就可以获取到config接口的需要的所有参数了。。。
一般来说,我们可以通过ajax请求后台,将appId、timestamp、nonceStr、signature获取到。。然后在回调函数中进行微信分享内容的设置了,,,
js代码见下。。。
$.ajax({ url:ip+'/wx/config', type:'post', data:{url:location.href}, success:function(res){ console.log(res); if(res.code==200){ wx.config({ debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: res.extend.appId, // 必填,公众号的唯一标识 timestamp: res.extend.timestamp, // 必填,生成签名的时间戳 nonceStr: res.extend.nonceStr, // 必填,生成签名的随机串 signature: res.extend.signature,// 必填,签名,见附录1 jsApiList: ['onMenuShareTimeline','onMenuShareAppMessage'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }); wx.ready(function(){ wx.onMenuShareAppMessage({ title: $("#showName").text(), // 分享标题 link: location.href, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致 imgUrl:$("#video").attr("poster"), // 分享图标 success: function () { alert("分享到朋友成功"); }, cancel: function () { alert("取消分享"); } }); wx.onMenuShareTimeline({ title: $("#showName").text(), // 分享标题 link: location.href, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致 imgUrl:$("#video").attr("poster"), // 分享图标 success: function () { alert("分享到朋友圈成功"); }, cancel: function () { alert("取消分享"); } }); }); } } });