之前都很少涉及到微信相关的开发,最近公司要做一个微信公众号,且其中涉及到自定义页面的分享,故在此记录下自定义分享信息链接的过程。
至于微信公众号的申请及认证在此就不多说。
按 微信公众号JSSDK文档 的步骤来,步骤一、二就不说了,说下步骤三的config参数的获取,
config需要的参数入上图,时间戳跟签名随机串后台直接生成就好,注意时间戳单位是秒不是毫秒,jsApiList是你要调用哪些接口,在JSSDK找到你需要的相应的接口;然后主要就是signature的获取;要想获取signature需要经过三步
- 通过公众号的 APPID 和 SECRET 先获取到 access_token (要注意的是access_token每日的获取次数是有限制的,且access_token每次请求都有2个小时时效,根据具体情况需做缓存);
- 通过 access_token 去再去请求获取jsapi_ticket接口,获得 ticket;
- 将 ticket,时间戳,随机串,还有你需要分享的页面的URL,四个参数按照字段名的 ASCII 码从小到大排序(字典序)后做sha1加密最后得到 signature。
以下是签名说明:
接下来是步骤四,微信分享重写,相关参数都有说明也很容易理解:
最后贴上我的代码实现
这是前端 js
$(function(){
var $url = location.href.split('#')[0];
$.ajax({
type: "post",
url: "/获取signature的路径",
data: {"pageUrl":$url},
traditional:true,
success: function (data) {
console.log(data);
if (data.code == 1) {
wx_fxconfig(data.result);
} else {
jqalert({
title: '提示',
content: '获取信息失败,请刷新页面重试'
})
}
},
error: function (xhr) {
console.log(xhr);
jqalert({
title: '提示',
content: '获取信息异常,请刷新页面重试'
})
}
});
});
function wx_fxconfig ($result) {
wx.config({
//debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: $result.appid, // 必填,公众号的唯一标识
timestamp: $result.timestamp, // 必填,生成签名的时间戳
nonceStr: $result.noncestr, // 必填,生成签名的随机串
signature: $result.signature,// 必填,签名
jsApiList: ['updateAppMessageShareData','updateTimelineShareData'] // 分享朋友及朋友圈及qq
});
/*微信分享重写*/
wx.ready(function(){
var title = "";
var desc = "";
var imgUrl = "";
var link = "";
//分享朋友
wx.updateAppMessageShareData({
title: title,//分享标题
link: link,//分享链接
imgUrl: imgUrl,// 分享图标
desc: desc, // 分享描述
success: function () {
// 设置成功
}
});
//分享朋友圈
wx.updateTimelineShareData({
title: title,// 分享标题
link: link,//分享链接
imgUrl: imgUrl,// 分享图标
success: function () {
// 设置成功
}
});
//获取用户所在位置经纬度
wx.getLocation({
type: 'wgs84', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02'
success: function (res) {
var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90
var longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。
var speed = res.speed; // 速度,以米/每秒计
var accuracy = res.accuracy; // 位置精度
$('#addInfo').val(longitude + "," + latitude);
}
});
});
}
这是后端获取signature签名
@RequestMapping(value = "/getWxConfig", method = RequestMethod.POST)
public Result getWxConfig (String pageUrl, HttpServletRequest request) {
String accessToken = null;
String ticket = null;
try {
accessToken = getAccessToken();
} catch (Exception e) {
logger.error("请求accessToken异常");
return Result.error("获取accessToken异常");
}
try {
String ticketUrl = TICKET_URL + accessToken;
JSONObject ticketObj = readRespFromGet(ticketUrl);
if (ticketObj == null) {
return Result.error("获取ticket失败");
}
if ("0".equals(ticketObj.getString("errcode"))) {
ticket = ticketObj.getString("ticket");
} else {
logger.info("获取ticket失败:{}", ticketObj.getString("errmsg"));
return Result.error("获取ticket失败");
}
} catch (Exception e) {
logger.error("请求ticket异常");
return Result.error("获取ticket异常");
}
Map<String, String> returnMap = new HashMap<>();
try {
String noncestr = UUID.randomUUID().toString();
String timestamp = String.valueOf(System.currentTimeMillis()/1000);
SortedMap itemMap = new TreeMap();
itemMap.put("jsapi_ticket", ticket);
itemMap.put("url", pageUrl);
itemMap.put("noncestr", noncestr);
itemMap.put("timestamp", timestamp);
String signature = SignUtil.signature(itemMap);
returnMap.put("signature", signature);
returnMap.put("noncestr", noncestr);
returnMap.put("timestamp", timestamp);
returnMap.put("appid", APPID);
} catch (Exception e) {
logger.info("生成签名失败:{}", e);
return Result.error("生成签名失败");
}
return Result.success(returnMap);
}
private JSONObject readRespFromGet(String getUrl) throws IOException {
JSONObject object = null;
if (StringUtils.isBlank(getUrl)) {
return object;
}
String respStr = HttpRequestUtils.readContentFromGet(getUrl);
if (StringUtils.isBlank(respStr)) {
logger.info("===请求返回空参数===");
return object;
}
object = JSONObject.parseObject(respStr);
return object;
}
private String getAccessToken() throws Exception {
String accessToken = redisService.get(APPID);
if (StringUtils.isNotBlank(accessToken)) {
return accessToken;
}
String accessTokenUrl = ACCESS_TOKEN_URL + APPID + "&secret=" + SECRET;
JSONObject tokenObj = readRespFromGet(accessTokenUrl);
if (tokenObj == null) {
logger.info("获取token失败");
throw new Exception("获取token失败");
}
accessToken = tokenObj.getString("access_token");
if (StringUtils.isBlank(accessToken)) {
logger.info("获取access_token失败:{}", tokenObj.getString("errmsg"));
throw new Exception("获取token失败");
}
Integer expiresIn = tokenObj.getInteger("expires_in");
if (expiresIn != null) {
redisService.set(APPID, accessToken);
redisService.expire(APPID, expiresIn);
}
return accessToken;
}
下面是SignUtil工具类:
public class SignUtil {
public static String signature(SortedMap<String,String> items){
StringBuilder forSign= new StringBuilder();
for(String key:items.keySet()){
forSign.append(key).append("=").append(items.get(key)).append("&");
}
forSign.setLength(forSign.length()-1);
String result = encryptSHA1(forSign.toString());
return result;
}
public static String encryptSHA1(String content){
try {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.update(content.getBytes());
byte messageDigest[] = digest.digest();
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < messageDigest.length; i++) {
String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
if (shaHex.length() < 2) {
hexString.append(0);
}
hexString.append(shaHex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
}
最后,在你需要分享的相关页码引入以上js文件及JSSDK步骤二中说明的需要引入的js文件 http://res2.wx.qq.com/open/js/jweixin-1.4.0.js
以上,自己记录下,也希望帮到有需要的你们。