springboot+H5实现微信分享
Post date:
Author: cyy
Number of comments: no comments
准备工作:
1.得有一个公众号,且实名认证通过
2.配置js安全域名
3.配置APPID和AppSecret
4.配置IP白名单
微信分享需要后端支持,先上后端代码:
controller
import com.cyy.model.dto.common.ResultVo;
import com.cyy.utils.ResultVoUtil;
import io.swagger.annotations.Api;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
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;
/**
* @Description 微信分享
* @author cyy
* @date 2021/2/12 21:13
* @Param
* @return
*/
@RestController
@RequestMapping("/wechat")
@CrossOrigin
@Api(value = "WechatController", tags = "微信分享")
public class WechatController {
private static final Logger logger = LoggerFactory.getLogger(WechatController.class);
// 公众号appid
private static final String APPID = "这里改成你自己的";
// 公众号开发者秘钥
private static final String APPSECRET = "这里改成你自己的";
private static final String GETACCESSTOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
private static final String GETTICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
private Long TICKET_TIMESTAMP;
private String JSAPI_TICKET;
/**
* @Description h5微信分享数据准备
* @author cyy
* @date 2021/2/12 21:16
* @Param [url] 前端分享页面服务器路径(一定要前端获取分享页面地址,不要后端写死,写死容易造成签名错误问题出现)
* @return UniformResultTemplate<Map<String,String>>
*/
@RequestMapping(value = "/getShareData")
@ResponseBody
public ResultVo<Map<String, String>> getShareData(String url) throws IOException {
long currentTimestamp = System.currentTimeMillis() / 1000;
if ((StringUtils.isEmpty(JSAPI_TICKET) && TICKET_TIMESTAMP == null) || (StringUtils.isNotEmpty(JSAPI_TICKET) && TICKET_TIMESTAMP != null && TICKET_TIMESTAMP + 7200 < currentTimestamp)) {
JSAPI_TICKET = getTicket(url);
TICKET_TIMESTAMP = System.currentTimeMillis() / 1000;
}
Map<String, String> ret = sign(JSAPI_TICKET, url);
return ResultVoUtil.success(ret);
}
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;
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("app_id", APPID);
ret.put("nonceStr", nonce_str);
ret.put("timestamp", timestamp);
ret.put("signature", signature);
return ret;
}
private static String create_nonce_str() {
String uuid = UUID.randomUUID().toString().replace("-","");
return uuid.substring(0, 15).toUpperCase();
}
private static String create_timestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
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 getTicket(String url) throws IOException {
// 获取“access_token”,建议放于缓存或者数据库中,定时刷新
logger.error("参数url: {}", url);
String getAccessTokenPath = GETACCESSTOKEN_URL.replace("APPID", APPID).replace("APPSECRET", APPSECRET);
logger.error("参数getAccessTokenPath: {}", getAccessTokenPath);
com.alibaba.fastjson.JSONObject jsonObject = doGetStr(getAccessTokenPath);
logger.error("参数jsonObject: {}", jsonObject);
String access_token = jsonObject.getString("access_token");
logger.error("参数access_token: {}", access_token);
// 根据“access_token”获取“jsapi_ticket”
String getTicketPath = GETTICKET_URL.replace("ACCESS_TOKEN", access_token);
logger.error("参数getTicketPath: {}", getTicketPath);
com.alibaba.fastjson.JSONObject jsonObject1 = doGetStr(getTicketPath);
logger.error("参数jsonObject1: {}", jsonObject1);
String ticket = jsonObject1.getString("ticket");
logger.error("参数ticket: {}", ticket);
return ticket;
}
/**
* 编写Get请求的方法。但没有参数传递的时候,可以使用Get请求
*
* @param url 需要请求的URL
* @return 将请求URL后返回的数据,转为JSON格式,并return
*/
public static JSONObject doGetStr(String url) throws IOException {
DefaultHttpClient client = new DefaultHttpClient();//获取DefaultHttpClient请求
HttpGet httpGet = new HttpGet(url);//HttpGet将使用Get方式发送请求URL
JSONObject jsonObject = null;
HttpResponse response = client.execute(httpGet);//使用HttpResponse接收client执行httpGet的结果
HttpEntity entity = response.getEntity();//从response中获取结果,类型为HttpEntity
if (entity != null) {
String result = EntityUtils.toString(entity, "UTF-8");//HttpEntity转为字符串类型
jsonObject = JSONObject.parseObject(result);//字符串类型转为JSON类型
}
return jsonObject;
}
}
再来编写前端的
<script type="text/javascript" src="https://res2.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
async setUpWechatShared () {
let that = this;
await this.$get('/wechat/getShareData?url=' + window.location.href)
.then((res) => {
wx.config({
debug: false,
appId: res.data.data.app_id,
timestamp: res.data.data.timestamp,
nonceStr: res.data.data.nonceStr,
signature: res.data.data.signature,
jsApiList: [
'checkJsApi',
'onMenuShareTimeline',
'onMenuShareAppMessage'
]
});
wx.ready(function() {
let url = window.location.href.indexOf('?') ? window.location.href.split('?')[0] : window.location.href;
wx.onMenuShareTimeline({
title: that.newsDetail.title || '', // 分享标题
link: url, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: 'https://www.tootootool.com/wp-content/uploads/2020/10/cropped-logo-1.png', // 分享图标
success: function() {
// 用户确认分享后执行的回调函数
}
});
wx.onMenuShareAppMessage({
title: that.newsDetail.title || '', // 分享标题
desc: that.newsDetail.summary || '', // 分享描述
link: url, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: 'https://www.tootootool.com/wp-content/uploads/2020/10/cropped-logo-1.png', // 分享图标
success: function() {
// 用户确认分享后执行的回调函数
}
});
});
}).catch(error => {
console.error('接口:/api/wechat/config,' + error)
})
}
页面加载时,请求接口
可以在微信这里校验我们生产的和微信的是否一致
https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
最终,在微信里分享会如下: