使用场景:wap端分享链接
官方网站:https://mp.weixin.qq.com
开发条件
- 申请微信公众平台账号
- 获取AppId,AppSecret
- 添加ip白名单
- 绑定域名并下载txt文档
配置截图
后台开发步骤
- 获取access_token(https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183)
- 获取ticket(https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115)
- 生成签名,并向前台响应如下参数
前台开发步骤
- 引入js文件(https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115)
- Ajax请求后台获取如下参数
- 在wx.ready中调用需要使用的接口,并给相应的参数值
注意事项
1 access_token的时效为7200s,调用接口的频次有上限,将token妥善保管。减少access_token获取的次数。
2 必须绑定域名
3 .txt文档放到域名跟目录下
package com.dsj.data.web.utils;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Sign {
private static final Logger LOGGER = LoggerFactory.getLogger(Sign.class);
public static void main(String[] args) {
String jsapi_ticket = "sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg";
// 注意 URL 一定要动态获取,不能 hardcode
String url = "http://example.com";
Map<String, String> ret = sign(jsapi_ticket, url);
for (Map.Entry entry : ret.entrySet()) {
System.out.println(entry.getKey() + ", " + entry.getValue());
}
};
public static Map<String, String> sign(String jsapi_ticket, String url) {
Map<String, String> ret = new HashMap<String, String>();
String nonce_str = create_nonce_str();
String timestamp = create_timestamp();
String string1;
String signature = "";
//注意这里参数名必须全部小写,且必须有序
string1 = "jsapi_ticket=" + jsapi_ticket +
"&noncestr=" + nonce_str +
"×tamp=" + timestamp +
"&url=" + url;
System.out.println(string1);
try
{
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(string1.getBytes("UTF-8"));
signature = byteToHex(crypt.digest());
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
ret.put("url", url);
ret.put("jsapi_ticket", jsapi_ticket);
ret.put("nonceStr", nonce_str);
ret.put("timestamp", timestamp);
LOGGER.info(" sign timestamp: {}", timestamp);
LOGGER.info(" sign nonce_str:{}", nonce_str);
LOGGER.info(" sign signature:{}", signature);
ret.put("signature", signature);
return ret;
}
private static 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;
}
private static String create_nonce_str() {
return UUID.randomUUID().toString();
}
private static String create_timestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
}
package com.dsj.data.wap.wx;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;
import com.dsj.common.utils.json.JsonMapper;
import com.dsj.common.utils.redis.one.RedisPoolUtil;
import com.dsj.common.utils.spring.ConfigUtils;
import com.dsj.data.web.utils.Sign;
@Controller
@RequestMapping("weixinIndex")
public class WXShareController {
private static final Logger LOGGER = LoggerFactory.getLogger(WXShareController.class);
private RestTemplate httpClientRestTemplate = new RestTemplate();
@RequestMapping("getSLBWXInfoForShare")
@ResponseBody
public Map<String, String> getSLBWXInfoForShare(String url) {
url.replace("?from=singlemessage&isappinstalled=0", "");
Map<String, String> sign = sign(url);
return sign;
}
//1微信公众号需要设置白名单 2. access_token时效性为两小时,每天有请求次数限制,存放redis/session 3测试必须要有域名,且端口为80 (项目名可有可无)
@SuppressWarnings("unchecked")
public Map<String, String> sign(String url) {
LOGGER.info("share sign start:{}", url );
Map<String, String> sign = new HashMap<String, String>();
//String nonceStr = "44e98c4fa5cb5c85dfff1a178673ec97";
//String appId = "wxf750030c2d7f3ee2";
String nonceStr = ConfigUtils.instance.getWxNonceStr();
String appId = ConfigUtils.instance.getWxFxApi();
String accessToken = RedisPoolUtil.get("wxAccessToken");
String forObject = "";
JsonMapper jsonMapper = JsonMapper.nonDefaultMapper();
if (StringUtils.isBlank(accessToken)) {
// 微信分享签名
String refreshToken = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+ appId +"&secret=" + nonceStr;
forObject = httpClientRestTemplate.getForObject(refreshToken, String.class, new HashMap<String, Object>());
LOGGER.info("wei xin rollback data: {}", forObject);
Map<String, Object> fromJson = jsonMapper.fromJson(forObject, Map.class);
Object object = fromJson.get("access_token");
accessToken = (String)object;
RedisPoolUtil.setex("wxAccessToken", accessToken, 5400);//设置一个半小时时效性
LOGGER.info("accessToken from weChet:{}", accessToken);
}else{
LOGGER.info("accessToken from redis:{}", accessToken);
}
String getTicket = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+ accessToken +"&type=jsapi";
forObject = httpClientRestTemplate.getForObject(getTicket, String.class, new HashMap<String, Object>());
Map<String, Object> fromJson = jsonMapper.fromJson(forObject, Map.class);
String errmsg = (String)fromJson.get("errmsg");
LOGGER.info("result:{}", errmsg);
if (errmsg.equals("ok")) {
String ticket = (String)fromJson.get("ticket");
LOGGER.info("weixin share get ticket:{}", ticket);
sign = Sign.sign(ticket, url);
sign.put("appId", appId);
LOGGER.info("weixin share sign end:{}", sign);
}
return sign;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="baidu-site-verification" content="GuW0deLRPn" />
<meta charset="UTF-8">
<title>测试支付</title>
<meta content="支付" name="keywords">
<meta content="测试支付" name="description">
<#include "common/taglibs.ftl">
<link rel="icon" href="${ctx}/static/front/img/favicon.ico" type="image/x-icon">
<link rel="shortcut icon" href="${ctx}/static/front/img/favicon.ico" type="image/x-icon">
<script src="${ctx }/static/front/js/jquery.js"></script>
</head>
<body>
<!-- 分享 -->
<div class="bdsharebuttonbox" data-tag="share_1">
<a class="bds_tsina" data-cmd="tsina"></a>
<a class="bds_weixin" data-cmd="weixin"></a>
<a class="bds_qzone" data-cmd="qzone"></a>
<a class="bds_sqq" data-cmd="sqq"></a>
</body>
<script type="text/javascript">
//分享
var shareTitle = '分享标题';
var shareName = '分享名称';
//分享
window._bd_share_config = {
"common": {
"bdSnsKey": {'tsina': '1546630873'},
'bdText': shareName,
"bdDesc": shareTitle,
"bdMini": "2",
'bdPic': 'http://dasouk.oss-cn-qingdao.aliyuncs.com/upload/pic/20171114104504942098.jpg',
"bdMiniList": false,
"bdStyle": "1",
"bdSize": "24",
"bdPopupOffsetLeft": "-235"
},
share: [{
"bdSize": 24
}]
};
with (document)0[(getElementsByTagName('head')[0] || body).appendChild(createElement('script')).src = 'http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion=' + ~(-new Date() / 36e5)];
setInterval(function () {
$("#bdshare_weixin_qrcode_dialog").css("height", "320px");
}, 300)
</script>
<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
<script>
$(function () {
/* 微信分享 */
var URL = window.location.href;
$.ajax({
url: "${ctx}/weixinIndex/getWXInfoForShare",
type: "post",
dataType: "json",
data: {url: URL},
success: function (data) {
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: data.appId, // 必填,公众号的唯一标识
timestamp: data.timestamp, // 必填,生成签名的时间戳
nonceStr: data.nonceStr, // 必填,生成签名的随机串
signature: data.signature,// 必填,签名,见附录1
jsApiList: [
'onMenuShareAppMessage',//分享给朋友
'onMenuShareTimeline',//分享到朋友圈
'onMenuShareQQ',//分享到QQ
'onMenuShareQZone'//分享到QQ空间
] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
//微信分享
wx.ready(function () {
/* 分享给朋友 */
wx.onMenuShareAppMessage({
title: '高超杰测试', // 分享标题
desc: '业绩不错!', // 分享描述
imgUrl: 'http://dasouk.oss-cn-qingdao.aliyuncs.com/upload/pic/20171017101400326813.png',
type: 'link', // 分享类型,music、video或link,不填默认为link
link: URL, // 分享链接
dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
success: function () {
//alert("分享成功");
},
cancel: function () {
// 用户取消分享后执行的回调函数
}
});
/* 分享到朋友圈 */
wx.onMenuShareTimeline({
title: '123123', // 分享标题
desc: '1312!', // 分享描述
link: URL, // 分享链接
imgUrl: 'http://dasouk.oss-cn-qingdao.aliyuncs.com/upload/pic/20171017101400326813.png', // 分享图标
success: function () {
},
cancel: function () {
// 用户取消分享后执行的回调函数
}
});
/* 分享到QQ */
wx.onMenuShareQQ({
title: '123123', // 分享标题
desc: '123123!', // 分享描述
link: URL, // 分享链接
imgUrl: 'http://dasouk.oss-cn-qingdao.aliyuncs.com/upload/pic/20171017101400326813.png', // 分享图标
success: function () {
},
cancel: function () {
// 用户取消分享后执行的回调函数
}
});
/* 分享到QQ空间 */
wx.onMenuShareQZone({
title: '12312', // 分享标题
desc: '123123!', // 分享描述
link: URL, // 分享链接
imgUrl: 'http://dasouk.oss-cn-qingdao.aliyuncs.com/upload/pic/20171017101400326813.png', // 分享图标
success: function () {
},
cancel: function () {
// 用户取消分享后执行的回调函数
}
});
});
}
})
});
</script>
</html>