个人亲测通过
用微信打开一个网页,选择右上角的“发送给朋友”后,收到的消息是这样的:
而为了推广效果,我们更希望能自定义标题、描述、访问连接和图片,效果如下图:
下面介绍下怎样来实现这个功能
准备工作
需要一个认证的微信公众号,一定要确定认证
在登录微信公众平台https://mp.weixin.qq.com
在公众号设置–>功能设置,填写设置Js接口安全域名
Js安全域名是需要把微信提供的文件,放在指定域名或者目录下面可以访问的。
1,引用js
jquery-1.8.3.min.js
https://res.wx.qq.com/open/js/jweixin-1.0.0.js
注意,如果自己的域名模式是https模式,要使用https模式,不然会出现mixed content block,微信js不会执行
JS-sdk中的方法要在获取signature之后再执行,不然有可能会执行错误等,同时分享的调用要在wx.ready方法体里面执行,即微信配置都okay的情况下在执行。
2,页面添加js代码
<script type="application/javascript">
var wxParam = {
title: "title",// 分享标题(自行修改)
desc: 'desc', // 分享描述(自行修改)
link: 'link', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致(自行修改)
imgUrl: 'link', // 分享图标,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致(自行修改)
type: "link",//分享类型,music、video或link,不填默认为link,(自行修改)
}
var pageUrl = {
url: (window.location.href).split('#')[0]
};
$(function () {
$.ajax({
url: "https://www.***.com/***/wxConfig",//获取微信signature的接口(自行修改)
type: "get",
data: {
link: encodeURIComponent(pageUrl.url)//固定当前页面访问路径,encodeURIComponent是处理后面带参数问题(&符号问题)java代码的使用URLDecoder.decode(link, "UTF-8")接受
},
async: false,//同步操作
cache: false,
dataType: 'json', <!--jsonp是Ajax专门为了应对跨域而提供的一个解决方案-->
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', 'onMenuShareWeibo', 'onMenuShareQZone']// 必填,需要使用的JS接口列表,所有JS接口列表见附录2 , 'onMenuShareTimeline', 'onMenuShareQQ', 'onMenuShareWeibo', 'onMenuShareQZone'
// 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
wx.ready(function () {
wx.onMenuShareAppMessage({
title: wxParam.title,// 分享标题
desc: wxParam.desc, // 分享描述
link: wxParam.link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: wxParam.imgUrl, // 分享图标
type: wxParam.link,//分享类型,music、video或link,不填默认为link,\
success: function () {
if (wxParam.successFn) {
wxParam.successFn();
}
}, cancel: function () {
if (wxParam.cancelFn) {
wxParam.cancelFn();
}
}
});
//分享到朋友圈
wx.onMenuShareTimeline({
title: wxParam.title,
link: wxParam.link,
imgUrl: wxParam.imgUrl,
success: function () {
if (wxParam.successFn) {
wxParam.successFn();
}
}, cancel: function () {
if (wxParam.cancelFn) {
wxParam.cancelFn();
}
}
});
//分享到QQ
wx.onMenuShareQQ({
title: wxParam.title,
desc: wxParam.desc,
link: wxParam.link,
imgUrl: wxParam.imgUrl,
success: function () {
if (wxParam.successFn) {
wxParam.successFn();
}
}, cancel: function () {
if (wxParam.cancelFn) {
wxParam.cancelFn();
}
}
});
//分享到腾讯微博
wx.onMenuShareWeibo({
title: wxParam.title,
desc: wxParam.desc,
link: wxParam.link,
imgUrl: wxParam.imgUrl,
success: function () {
if (wxParam.successFn) {
wxParam.successFn();
}
}, cancel: function () {
if (wxParam.cancelFn) {
wxParam.cancelFn();
}
}
});
//分享到QQ空间
wx.onMenuShareQZone({
title: wxParam.title,
desc: wxParam.desc,
link: wxParam.link,
imgUrl: wxParam.imgUrl,
success: function () {
if (wxParam.successFn) {
wxParam.successFn();
}
}, cancel: function () {
if (wxParam.cancelFn) {
wxParam.cancelFn();
}
}
});
wx.error(function (res) {
//alert(res);
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
});
});
},
error: function (data) {
console.log(data);
}
})
});
</script>
3,java代码
/**
* 获取分享数据
*/
@RequestMapping(value = "/wxConfig", method = RequestMethod.GET)
@ResponseBody
public R wxConfig(@RequestParam String link) throws UnsupportedEncodingException {
String appid = "wxf7******9c9";//公众号的唯一标识(开发者ID(AppID))
String secret = "cafb0ad5******9c9f286";//开发者密码(AppSecret)
Map<String, String> ret = new HashMap<String, String>();
String ticket = jedies.getValue(JedisKeyPrefix.JEDIS_KEY_PREFIX_WECHAT_TICKET, "jsapi_ticket");//从redis获取jsapi_ticket
String url = jedies.getValue(JedisKeyPrefix.JEDIS_KEY_PREFIX_WECHAT_TICKET, "url");//从redis获取url
link = URLDecoder.decode(link, "UTF-8");//url地址参数乱问处理
if (url != null && !link.startsWith("https:")) {
link = link.replaceAll("http", "https");
}
if (StringUtil.isEmpty(ticket) || (StringUtil.isNotEmpty(url) && (!url.equals(link)))) {
ret = WxJSUtil.sign(appid, secret, link, null);
for (Map.Entry entry : ret.entrySet()) {
System.out.println(entry.getKey() + "=" + entry.getValue());
//把相关参数放入redis
if ("jsapi_ticket".equals(entry.getKey())) {
jedies.setValue(JedisKeyPrefix.JEDIS_KEY_PREFIX_WECHAT_TICKET, "jsapi_ticket", entry.getValue().toString(), 6000);
} else if ("timestamp".equals(entry.getKey())) {
jedies.setValue(JedisKeyPrefix.JEDIS_KEY_PREFIX_WECHAT_TICKET, "timestamp", entry.getValue().toString(), 6000);//生成签名的时间戳
} else if ("nonceStr".equals(entry.getKey())) {
jedies.setValue(JedisKeyPrefix.JEDIS_KEY_PREFIX_WECHAT_TICKET, "nonceStr", entry.getValue().toString(), 6000);//生成签名的随机串
} else if ("signature".equals(entry.getKey())) {
jedies.setValue(JedisKeyPrefix.JEDIS_KEY_PREFIX_WECHAT_TICKET, "signature", entry.getValue().toString(), 6000);//签名,见附录1
} else if ("url".equals(entry.getKey())) {
jedies.setValue(JedisKeyPrefix.JEDIS_KEY_PREFIX_WECHAT_TICKET, "url", entry.getValue().toString(), 6000);
}
}
} else {
String timestamp = jedies.getValue(JedisKeyPrefix.JEDIS_KEY_PREFIX_WECHAT_TICKET, "timestamp");
String nonceStr = jedies.getValue(JedisKeyPrefix.JEDIS_KEY_PREFIX_WECHAT_TICKET, "nonceStr");
String signature = jedies.getValue(JedisKeyPrefix.JEDIS_KEY_PREFIX_WECHAT_TICKET, "signature");
ret.put("url", url);
ret.put("jsapi_ticket", ticket);
ret.put("nonceStr", nonceStr);
ret.put("timestamp", timestamp);
ret.put("signature", signature);
}
return R.ok().put("appid", appid).put("map", ret);
}
WxJSUtil.java文件
import net.sf.json.JSONObject;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* 微信分享参数处理
*/
public static Map<String, String> sign(String appid, String secret, String url, String jsapi_ticket) {
Map<String, String> ret = new HashMap<String, String>();
if (jsapi_ticket == null) {
jsapi_ticket = getJSApiTicket(appid, secret);
}
String nonce_str = create_nonce_str();
String timestamp = create_timestamp();
String signature = "";
//注意这里参数名必须全部小写,且必须有序
String 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());
System.out.println("JSSDK签名:" + signature);
} 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);
ret.put("signature", signature);
return ret;
}
/***
* 获取jsapiTicket
*/
public static String getJSApiTicket(String appid, String secret) {
//获取token
String acess_token = getAccessToken(appid, secret);
String backData = requestHttp(
"https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="
+ acess_token + "&type=jsapi",
"get", "");
String ticket = (String) JSONObject.fromObject(backData).get("ticket");
System.out.println("调用微信jsapi的凭证票为:" + ticket);
return ticket;
}
/***
* 获取acess_token
*/
public static String getAccessToken(String appid, String secret) {
String result = requestHttp(
"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
+ appid + "&secret=" + secret,
"get", "");
JSONObject jsonObject = JSONObject.fromObject(result);
System.out.println("access_token" + result);
String token = jsonObject.getString("access_token");
return token;
}
public static String requestHttp(String path, String method, String params) {
HttpURLConnection connection = null;
String result = "";
try {
URL url = new URL(path);
connection = (HttpURLConnection) url.openConnection();
if (method.equalsIgnoreCase("GET")) {
connection.connect();
} else if (method.equalsIgnoreCase("POST")) {
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);
connection.connect();
OutputStream os = connection.getOutputStream();
os.write(params.getBytes("UTF-8"));
os.close();
}
BufferedReader reader = new BufferedReader(new InputStreamReader(
connection.getInputStream(), "UTF-8"));
String lines;
StringBuilder sb = new StringBuilder();
while ((lines = reader.readLine()) != null) {
sb.append(lines);
}
result = sb.toString();
reader.close();
connection.disconnect();
return result;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
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);
}
附上获取signature处理代码,在获取signature之前,需要获取accessToken 和 对应的Ticket,这两个方式都比较简单,不在列举
来源:CSDN
作者:夏婉妹妹
链接:https://blog.csdn.net/m0_37711292/article/details/103714365