微信内置浏览器第三方网页分享链接给朋友以及转发到朋友圈无链接图片和链接描述的问题
解决问题:微信内置浏览器第三方网页分享链接给朋友以及转发到朋友圈无链接图片和链接描述的问题
记录时间:2018-11-07 分享作者:小鹏
谨记:一定要按步骤一步一步来
先写一写思路:进入页面需要分享的jsp(html)页面之后 要调后台接口去拿数据(拿的数据跟当前的页面路径url有关,因此需要把当前页面的url 传给后台),之后把后台拿到的数据塞到当前页面进行配置(下面的 wx.config的一些内容),配置之后才可以监听用户点击发送给朋友以及分享到朋友圈的操作以及自定义转发的内容、图片和链接。
步骤一:绑定域名
先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。(备注:一定要是备案的安全域名)
步骤二:引入JS文件
引入JS文件只需要下面这一句就可以
<script src="https://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script> // 备注:切记一定要是 https 不然后面会使IOS系统不好用
步骤三:请求后台拿配置数据 这一步微信跳过去了 一定要注意
var urlBay = window.location.href.split('#')[0] // 当前页面的url ps:'#'前边的路径
$.ajax({
url: '${pageContext.request.contextPath}/goods/wxshare', //请求后台加载数据的路径改成你自己的
data: "urlBay=" + encodeURIComponent(urlBay), //强烈注意:这里需要这样写
success: function(data) { //此处的data为后台返回的json 数据
wx.config({
debug: false, //是否 开启调试模式,建议调试的时候debug 改为true
appId: data.appId, // 必填,公众号的唯一标识
timestamp: data.timestamp, // 必填,生成签名的时间戳
nonceStr: data.nonceStr, // 必填,生成签名的随机串
signature: data.signature, // 必填,签名,见附录1
jsApiList: [
'checkJsApi',
'updateAppMessageShareData',
'updateTimelineShareData',
'onMenuShareAppMessage',
'onMenuShareTimeline',
'showOptionMenu',
] // 必填,需要使用的JS接口列表 声明
});
wx.error(function(res) {
// alert("微信接口初始化失败;错误信息:"+res.toString());
});
window.onload = function() {
// alert("当前域名是:"+url);
}
wx.ready(function() {
wx.updateAppMessageShareData({
debug: false,
title: '鸿运当头汽车优惠卷', // 分享标题
desc: '鸿运当头汽车优惠卷,赶紧来抢!', // 分享描述
link: urlBay, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: "http://pic.58pic.com/58pic/17/30/55/058PICy58PICgd3_1024.jpg", // 分享图标
success: function() {
// 用户点击了分享后执行的回调函数
}
});
wx.updateTimelineShareData({
debug: false,
title: '分享标题', // 分享标题
desc: '分享描述', // 分享描述
link: urlBay, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: "http://pic.58pic.com/58pic/17/30/55/6263.jpg", // 分享图标
success: function() {
// 用户点击了分享后执行的回调函数
}
});
});
}
})
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
步骤四:后台获取签名数据 这一步微信也跳过去了 供给后台开发理解和使用
appId 以及secret 需要去公众号后台查看 并写到一个静态常量类里面就好
HttpRequestUtil 通过appId以及secret 访问微信公共接口获取token 以及ticket
public class HttpRequestUtil {
private static final Logger log = LoggerFactory.getLogger(HttpRequestUtil.class);
private static ObjectMapper objectMapper = new ObjectMapper();
/**
* http请求工具类,post请求
*
* @param url url
* @param params 参数值 仅支持String和list两种类型
* @return
* @throws Exception
*/
public static String httpPost(String url, Map<String, Object> params) throws Exception {
DefaultHttpClient defaultHttpClient = null;
BufferedReader bufferedReader = null;
try {
defaultHttpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("Content-Type", "application/json;charset=ut-8");
if (params != null) {
//转换为json格式并打印,不需要的你们可以不要
String jsonParams = objectMapper.writeValueAsString(params);
log.info("参数值:{}", jsonParams);
HttpEntity httpEntity = new StringEntity(jsonParams, "utf-8");
httpPost.setEntity(httpEntity);
}
HttpResponse httpResponse = defaultHttpClient.execute(httpPost);
if (httpResponse.getStatusLine().getStatusCode() != 200) {
String errorLog="请求失败,errorCode:"+httpResponse.getStatusLine().getStatusCode();
log.info(errorLog);
throw new Exception(url+errorLog);
}
//读取返回信息
String output;
bufferedReader=new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent(),"utf-8"));
StringBuilder stringBuilder=new StringBuilder();
while ((output=bufferedReader.readLine())!=null){
stringBuilder.append(output);
}
return stringBuilder.toString();
} catch (ClientProtocolException e) {
e.printStackTrace();
throw e;
}catch (IOException e){
e.printStackTrace();
throw e;
}finally {
if(defaultHttpClient!=null)
defaultHttpClient.getConnectionManager().shutdown();
if(bufferedReader!=null)
bufferedReader.close();
}
}
/**
* http请求工具类,get请求
* @param url
* @param params
* @param resonseCharSet
* @return
* @throws Exception
*/
public static String httpGet(String url, Map<String, String> params) throws Exception {
DefaultHttpClient defaultHttpClient = null;
BufferedReader bufferedReader = null;
try {
defaultHttpClient = new DefaultHttpClient();
if(params!=null){
StringBuilder stringBuilder=new StringBuilder();
Iterator<String> iterator=params.keySet().iterator();
String key;
while (iterator.hasNext()){
key=iterator.next();
Object val=params.get(key);
if(val instanceof List){
List v= (List) val;
for (Object o:v){
stringBuilder.append(key).append("=").append(o.toString()).append("&");
}
}else{
stringBuilder.append(key).append("=").append(val.toString()).append("&");
}
}
stringBuilder.deleteCharAt(stringBuilder.length()-1);
url=url+"?"+stringBuilder.toString();
log.info("url:{}",url);
}
HttpGet httpGet = new HttpGet(url);
httpGet.setHeader("Content-Type", "application/json;charset=ut-8");
HttpResponse httpResponse = defaultHttpClient.execute(httpGet);
if (httpResponse.getStatusLine().getStatusCode() != 200) {
String errorLog="请求失败,errorCode:"+httpResponse.getStatusLine().getStatusCode();
log.info(errorLog);
throw new Exception(url+errorLog);
}
//读取返回信息
String charSet="utf-8";
// if(resonseCharSet!=null && resonseCharSet.length>0)
// charSet=resonseCharSet[0];
String output;
bufferedReader=new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent(),charSet));
StringBuilder dataBuilder=new StringBuilder();
while ((output=bufferedReader.readLine())!=null){
dataBuilder.append(output);
}
return dataBuilder.toString();
} catch (ClientProtocolException e) {
e.printStackTrace();
throw e;
}catch (IOException e){
e.printStackTrace();
throw e;
}finally {
if(defaultHttpClient!=null)
defaultHttpClient.getConnectionManager().shutdown();
if(bufferedReader!=null)
bufferedReader.close();
}
}
}
WeixinUtil.java //封装的工具类
public class WeixinUtil {
public static boolean signatureCheck(String token,String timeStamp,String nonce,String signature) throws Exception{
List<String > list = new ArrayList<String>(3){
public String toString(){
return this.get(0)+this.get(1)+this.get(2) ;
}
} ;
list.add(token) ;
list.add(timeStamp) ;
list.add(nonce) ;
Collections.sort(list) ;
MessageDigest md = MessageDigest.getInstance("SHA-1") ;
byte[] digest = md.digest(list.toString().getBytes()) ;
String testStr = WeixinUtil.byteArrayToHexString(digest) ;
if(testStr.equalsIgnoreCase(signature.toUpperCase())){
return true;
}else{
return false ;
}
}
public static String signature(String jsapiTicket,String nonceStr,Long timestamp,String url) throws Exception{
String str = String.format("jsapi_ticket=%s&noncestr=%s×tamp=%d&url=%s",
jsapiTicket,nonceStr,timestamp,url) ;
MessageDigest md = MessageDigest.getInstance("SHA-1") ;
byte[] digest = md.digest(str.getBytes()) ;
String sigStr = WeixinUtil.byteArrayToHexString(digest) ;
return sigStr ;
}
public static String byteArrayToHexString(byte[] array){
String strDigest = "" ;
for(int i = 0 ;i<array.length;i++){
strDigest+=byteToHexString(array[i]) ;
}
return strDigest ;
}
public static String byteToHexString(byte ib){
char[] Digit = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'} ;
char [] ob = new char[2] ;
ob[0] = Digit[(ib >>> 4) & 0X0F] ;
ob[1] = Digit[ib &0X0F] ;
String s = new String(ob) ;
return s ;
}
public static String getWeiXinShareToken(String appId,String secret) throws Exception{
Map<String,String> maps = new HashMap<String,String>() ;
maps.put("grant_type", ShareConstants.grant_type) ;
maps.put("appid",appId) ;
maps.put("secret",secret);
try{
String result = HttpRequestUtil.httpGet(ShareConstants.GET_TOKEN_URL,null) ;
JSONObject jsonObject = JSONObject.parseObject(result) ;
String access_token = (String) jsonObject.get("access_token") ;
Integer expires_in = (Integer) jsonObject.get("expires_in") ;
System.out.println("xiaopeng---get--token--"+result);
if(access_token !=null && expires_in!=null && expires_in==7200)
return getJsApiTicket(access_token);
else
return null ;
}catch (Exception ex){
System.out.println("xiaopeng222"+ex.getStackTrace().toString());
throw new Exception("get Token failed");
}
}
public static String getJsApiTicket(String token) throws Exception{
Map<String,String> maps = new HashMap<String,String>() ;
maps.put("access_token",token);
maps.put("type",ShareConstants.type);
try{
String result = HttpRequestUtil.httpGet(ShareConstants.TICKET_URL_TEST,maps) ;
System.out.println("xiaopeng---get--ticket--"+result);
JSONObject jsonObject = JSONObject.parseObject(result) ;
Integer errcode = (Integer) jsonObject.get("errcode") ;
if(errcode==null || (errcode!=null &&errcode!=0)){
return null ;
}else{
String ticket = (String) jsonObject.get("ticket") ;
System.out.println("xiaopeng---get--ticket--"+ticket);
return ticket ;
}
}catch (Exception ex){
throw new Exception("getJsApi Ticket is failed") ;
}
}
}
SignBean.java //jsp通过接口取数据返回的实体类
public class SignBean {
private String appId;
private String jsapi_ticket;
private String nonceStr;
private String timestamp;
private String url;
private String signature;
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getJsapi_ticket() {
return jsapi_ticket;
}
public void setJsapi_ticket(String jsapi_ticket) {
this.jsapi_ticket = jsapi_ticket;
}
public String getNonceStr() {
return nonceStr;
}
public void setNonceStr(String nonceStr) {
this.nonceStr = nonceStr;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature;
}
}
Sign.java // 根据 ticket 和 url 获取签名工具类
public class Sign {
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);
//注意这里 要加上自己的appId
ret.put("appId", ShareConstants.appId);
ret.put("jsapi_ticket", jsapi_ticket);
ret.put("nonceStr", nonce_str);
ret.put("timestamp", timestamp);
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);
}
}
**步骤五:通过config接口注入权限验证配置 拿到后台的数据 上面jsp代码中的 data 直接点 . 出来就好 **
注意备注:
1.appId和secret 检查一定要公众号后台匹配对的
2.获取签名的 url 要为当前分享网页的url (微信分享出去之后会自动在后面添加一些信息 比如 from=singlemessage from=timeline 等)
3.获取 access_token 路径为 https://api.weixin.qq.com/cgi-bin/token
4.获取 ticket 路径为 https://api.weixin.qq.com/cgi-bin/ticket/getticket
支持开发完毕
切记一定要细心 细心再 细心
欢迎咨询