微信自定义分享功能实现
- 微信自定义分享功能实现
- 一、实现的关键
- 1.后端的任务
- 2.前台的任务
- 二、实现具体步骤
- 1、js安全域名配置(被分享的网址必须实现)
- 2、添加服务器配置(成为开发者)
- 3、生成签名signature
- (1)获取access_Token:
- (2)获取 jsapi_ticket :
- (3)用sha1加密算法得到signature:
- 4、将参数发送到前台:
- (1)后台总体方法:
- (2)前台JavaScript代码:
- 三、踩过的坑:
- (1)获取access_token时报错,提示某某IP不在白名单内:
- (2)公众号是个人订阅的,是没有调用分享接口权限的,除非微信认证过:
微信自定义分享功能实现
一、实现的关键
新手应明白一个概念:微信前台已经写好了所有微信功能的代码,如:微信分享给朋友、分享到朋友圈、拍照或从手机相册中选图接口。微信一开始调用的是默认的接口方法,我们只需给这些接口传递一些参数即可达到自定义功能的实现,本质上还是依赖微信前台的接口方法。就如同下面的任务需求:
要想实现目标需求就需要给微信的分享方法传递参数(标题、简介、图片):
但我们想前台能调用这些接口实现,就必须先进行权限验证。前台必须通过参数验证,才可调用微信接口,通过config方法验证:
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,生成签名的随机串
signature: '',// 必填,签名
jsApiList: [] // 必填,需要使用的JS接口列表
});
1.后端的任务
后台的任务就是将下面标明的四个参数传到前台:
2.前台的任务
(1)在下面标明的列表里加上你想传参或调用的微信接口:
(2)下面是自定义分享的实现例子:
<script type="text/javascript">
var shareUrl = decodeURIComponent(location.href.split('#')[0]);
var shareTitle="huilong资讯";
var shareImgUrl='https://up.enterdesk.com/edpic_360_360/5b/c6/9a/5bc69a3ccf8b5b5ffd33bcdea05c7ec2.jpg';
var timestamp;
var noncestr;
var signature;
var appId;
//获取签名
$.ajax({
type: "POST",
url: "/wx/share",
data:{url:shareUrl},
success: function(result){
timestamp=result.data.timestamp;
noncestr=result.data.noncestr;
signature=result.data.signature;
appId=result.data.appId;
wxShare();
}
});
function wxShare() {
//微信接口权限验证
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: appId, // 和获取Ticke的必须一样------必填,公众号的唯一标识
timestamp: timestamp, // 必填,生成签名的时间戳
nonceStr: noncestr, // 必填,生成签名的随机串
signature: signature,// 必填,签名,见附录1
jsApiList: [
'updateTimelineShareData'
] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
wx.ready(function () {
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,
// 所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。
// 对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
wx.updateTimelineShareData({
title: 'sdasd', // 分享标题
link: shareUrl, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: shareImgUrl, // 分享图标
success: function () {
// 设置成功
}
})
})
}
</script>
二、实现具体步骤
1、js安全域名配置(被分享的网址必须实现)
上面的第三步springBoot可以这么实现:
2、添加服务器配置(成为开发者)
详细看文档:微信开发文档的接入指南
配置文件上需要填写AppId( 开发者ID )、AppSecret( 开发者密码)、token(自定义):
# 微信开发环境配置
wx:
config:
appid: wx8368a21c304999ed
secret: a6a55025b0c8a16f43b64e985c3ccdd7
token: huilong
(2)controller层:
@RequestMapping(value = "/wx/checkWx")
public String checkWx(WxSendMsgRequest wxSendMsgRequest){
return weiXinService.checkWxUrl(wxSendMsgRequest);
}
(3)service层:
@RequestMapping(value = "/wx/share",method = RequestMethod.POST)
public Result<WxShareResponse> checkWx(String url){
WxShareResponse wxShareResponse = weiXinService.queryWxShare(url);
System.out.println(JSON.toJSON(wxShareResponse));
Result<WxShareResponse> result = new Result<>();
if (wxShareResponse!=null){
result.setCode(0);
result.setData(wxShareResponse);
}else {
result.setCode(500);
}
return result;
}
3、生成签名signature
下一节有后台全部代码。
(1)获取access_Token:
详细看文档:微信开发文档的获取access_Token方法
(2)获取 jsapi_ticket :
步骤和上面差不多
详细看文档: 微信开发文档 看附录一
(3)用sha1加密算法得到signature:
详细看文档: 微信开发文档 看附录
4、将参数发送到前台:
(1)后台总体方法:
application配置文件:
# 微信开发环境配置
wx:
config:
appid: wx8368a21c304999ed
secret: a6a55025b0c8a16f43b64e985c3ccdd7
token: huilong
1.service层:
@Service
public class WeiXinServiceImpl implements WeiXinService {
@Value("${wx.config.token}")
private String token;
@Value("${wx.config.appid}")
private String appId;
@Value("${wx.config.secret}")
private String secret;
@Resource
private RedisUtils redisUtils;
@Resource
private RestTemplate restTemplate;
/**
* 微信安全验证
* 微信要录入服务器配置
*
* @param wxSendMsgRequest 微信验证携带的参数
* @return
*/
@Override
public String checkWxUrl(WxSendMsgRequest wxSendMsgRequest) {
System.out.println("进入验证");
try{
String msg[] =new String[]{token,wxSendMsgRequest.getNonce(),wxSendMsgRequest.getTimestamp()};
Arrays.sort(msg);
String checkStr=msg[0]+msg[1]+msg[2];
//用sha1加密算法
String sign= getSha1(checkStr);
if (wxSendMsgRequest.getSignature().equals(sign)){
return wxSendMsgRequest.getEchostr();
}
}catch (Exception e){
e.printStackTrace();
}
return null;
}
/**
* 微信分享
*
* @param url
* @return 返回微信分享所需参数
*/
@Override
public WxShareResponse queryWxShare(String url) {
WxShareResponse wxShareResponse =new WxShareResponse();
//从缓存中获取ticket
String ticket;
String accessToken;
//调用微信api接口获取accessToken
String getTokenUrl="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appId+"&secret="+secret;
WxConfigResponse wxToken = restTemplate.getForObject(getTokenUrl, WxConfigResponse.class);
accessToken=wxToken.getAccess_token();
if (wxToken.getErrcode()!=null&&wxToken.getErrcode()!=0){
wxShareResponse.setErrcode(wxToken.getErrcode());
wxShareResponse.setErrmsg(wxToken.getErrmsg());
return wxShareResponse;
}
String getTicketUrl="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+accessToken+"&type=jsapi";
WxConfigResponse wxTicket = restTemplate.getForObject(getTicketUrl, WxConfigResponse.class);
ticket=wxTicket.getTicket();
System.out.println(wxTicket);
if (wxTicket.getErrcode()!=null&&wxTicket.getErrcode()!=0){
wxShareResponse.setErrcode(wxTicket.getErrcode());
wxShareResponse.setErrmsg(wxTicket.getErrmsg());
return wxShareResponse;
}
//结合url、ticket等生成加密签名
String noncestr= UUID.randomUUID().toString();
String timestamp= Long.toString(System.currentTimeMillis()/1000);
String getSign="jsapi_ticket="+ticket+"&noncestr="+noncestr+"×tamp="+timestamp+"&url="+url;
String signature=getSha1(getSign);
wxShareResponse.setNoncestr(noncestr);
wxShareResponse.setTimestamp(timestamp);
wxShareResponse.setSignature(signature);
wxShareResponse.setAppId(appId);
return wxShareResponse;
}
//sha1加密方法
public static String getSha1(String inStr) {
MessageDigest sha = null;
byte[] byteArray;
try {
sha = MessageDigest.getInstance("SHA");
byteArray= inStr.getBytes("UTF-8");
} catch (Exception e) {
System.out.println(e.toString());
e.printStackTrace();
return "";
}
byte[] md5Bytes = sha.digest(byteArray);
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++) {
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16) {
hexValue.append("0");
}
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}
}
2.controller层:
@RestController
public class WeiXinController {
@Autowired
private WeiXinServiceImpl weiXinService;
@RequestMapping(value = "/wx/checkWx")
public String checkWx(WxSendMsgRequest wxSendMsgRequest){
return weiXinService.checkWxUrl(wxSendMsgRequest);
}
@RequestMapping(value = "/wx/share",method = RequestMethod.POST)
public Result<WxShareResponse> checkWx(String url){
WxShareResponse wxShareResponse = weiXinService.queryWxShare(url);
System.out.println(JSON.toJSON(wxShareResponse));
Result<WxShareResponse> result = new Result<>();
if (wxShareResponse!=null){
result.setCode(0);
result.setData(wxShareResponse);
}else {
result.setCode(500);
}
return result;
}
}
(2)前台JavaScript代码:
//获取签名
$.ajax({
type: "POST",
url: "/wx/share",
data:{url:shareUrl},
success: function(result){
timestamp=result.data.timestamp;
noncestr=result.data.noncestr;
signature=result.data.signature;
appId=result.data.appId;
}
});
//微信接口权限验证
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: appId, // 和获取Ticke的必须一样------必填,公众号的唯一标识
timestamp: timestamp, // 必填,生成签名的时间戳
nonceStr: noncestr, // 必填,生成签名的随机串
signature: signature,// 必填,签名,见附录1
jsApiList: [
'updateTimelineShareData'
] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
三、踩过的坑:
(1)获取access_token时报错,提示某某IP不在白名单内:
要配置ip白名单,将报错的IP地址添加到这:
(2)公众号是个人订阅的,是没有调用分享接口权限的,除非微信认证过:
这里看一看自己公众号的权限: