您的位置:首页 > 编程语言 > Java开发

Java微信开发——分享功能的实现(Spring boot框架)

2017-01-14 10:39 1491 查看
问题与需求:h5页面的内容在微信分享后分享的内容无法定制,要自定义分享内容为该h5页面的标题,内容,图片等。 实现与排错:由于本人技术有限,基本都是参照网络上大神们提供的源码,在部分地方做了简单修改。感谢大神们的无私奉献!主要参考链接和实现代码如下: java开发微信分享到朋友圈功能 http://www.jb51.net/article/88690.htm
微信公众平台开发:JS-SDK之分享功能整理(Java)http://blog.csdn.net/dcb_ripple/article/details/52066708
实现】步骤一:参考微信公众平台的开发者文档https://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html了解开发步骤 步骤二:为了描述方便,我先把h5页面的js代码贴出,再描述其实现所依赖的java代码。1.1h5页面的js代码h5页面:(获取该页面中的title-标题 discuss-内容 传入wx.config中实现分享内容的定制)
ps.由于我的页面用了angularjs,在js中如果通过document.getElementById拿值总是为空所以在js中再次使用了ajax向后台取值!!很影响性能的做法,在js中如何拿到angularjs渲染后的值呢?还希望有知道的朋友指点一下。weshare.js代码:

//获取签名
$.ajax({
type: "GET",
url: "wshare/getSignature",
data:{url:url},
success: function(data){
console.log("success");
var objData=JSON.parse(data);
timestamp=objData.timestamp;
noncestr=objData.noncestr;
signature=objData.signature;
console.log(objData);
wxShare();
},
statusCode: {404: function(){
alert('page not found');
}}
});
function wxShare(){
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: 'wxca57e6589ccebff0', // 和获取Ticke的必须一样------必填,公众号的唯一标识
timestamp:timestamp, // 必填,生成签名的时间戳
nonceStr: noncestr, // 必填,生成签名的随机串
signature: signature,// 必填,签名,见附录1
jsApiList: [
'onMenuShareAppMessage','onMenuShareTimeline','onMenuShareTimeline','onMenuShareQQ','onMenuShareQZone'
] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
}
wx.ready(function(){
//config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,
//config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关
//接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。//----------“分享给朋友”
wx.onMenuShareAppMessage({
title:title, // 分享标题
desc:discuss, // 分享描述
link: url, // 分享链接
imgUrl: shareImgUrl, // 分享图标
success: function () {
// 用户确认分享后执行的回调函数、
},
cancel: function () {
// 用户取消分享后执行的回调函数
}
});
//------------"分享到朋友圈"
wx.onMenuShareTimeline({
title: title, // 分享标题
desc: discuss, // 分享描述
link: url, // 分享链接
imgUrl: shareImgUrl, // 分享图标
type: '', // 分享类型,music、video或link,不填默认为link
dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
success: function () {
// 用户确认分享后执行的回调函数、
},
cancel: function () {
// 用户取消分享后执行的回调函数
}
});
//-------------分享到QQ
wx.onMenuShareQQ({
title: title, // 分享标题
desc: discuss, // 分享描述
link: url, // 分享链接
imgUrl: shareImgUrl, // 分享图标
type: '', // 分享类型,music、video或link,不填默认为link
dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
success: function () {
// 用户确认分享后执行的回调函数、
},
cancel: function () {
// 用户取消分享后执行的回调函数
}
});
//-------------分享到QQ空间
wx.onMenuShareQZone({
title: title, // 分享标题
desc: discuss, // 分享描述
link: url, // 分享链接
imgUrl: shareImgUrl, // 分享图标
type: '', // 分享类型,music、video或link,不填默认为link
dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
success: function () {
// 用户确认分享后执行的回调函数、
},
cancel: function () {
// 用户取消分享后执行的回调函数
}
});});
wx.error(function(res){
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
console.log(res);
});
1.2java后台实现代码1.2.1 weixin.controller
package com.weixin.controller;import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import com.weixin.util.WeixinUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;import com.google.gson.Gson;
import com.weixin.model.Ticket;
import com.weixin.util.GetRandomStr;
import com.weixin.util.SignatureBean;/**
* Created by Administrator on 2017/1/9.
*/
@Controller
@RequestMapping("/wshare")
public class WeixinshareController {private static Ticket aticket = null;@RequestMapping("/getSignature")
public String getSignature( HttpServletRequest request,
HttpServletResponse response) throws IOException, ParseException{
//获取签名页面链接
String url = request.getParameter("url");
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//获取标签,并检查标签是否过期
if(aticket==null){//第一次访问,标签不存在。
aticket = executeTicket(response,"1",url,format);
return null;
}else{//标签存在,判断标签是否超时
String oldAcquiretime = aticket.getAcquiretime();
long difference=format.parse(format.format(new Date())).getTime()-format.parse(oldAcquiretime).getTime();
if(difference>7100000){//标签超时,重新到微信服务器请求标签超时时间为7200秒(7200000毫秒)
aticket = executeTicket(response,"2",url,format);
return null;
}else{//标签未超时
/**
* 注意事项
* 1.签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。
* 2.签名用的url必须是调用JS接口页面的完整URL。
* 3.出于安全考虑,开发者必须在服务器端实现签名的逻辑。
*
****根据第1点要求 signature 配置的时候很容易出错,需要把生成 Ticket的 noncestr和 timestamp传给客户端***
*/
System.out.print("ticket:"+aticket.getTicket());
String signature = signature(aticket.getTicket(),aticket.getTimestamp(),aticket.getNoncestr(),url);
SignatureBean signatureBean = new SignatureBean();
signatureBean.setNoncestr(aticket.getNoncestr());
signatureBean.setSignature(signature);
signatureBean.setTimestamp(aticket.getTimestamp());
signatureBean.setUrl(url);
response.setContentType("text/html;charset=UTF-8");
response.getWriter().print(new Gson().toJson(signatureBean));
return null;
}
}}
/**
更新和获取ticket的方法,因为用的solr所以更新和新增是一样的ID无则添加,有则更新
*/
public Ticket executeTicket(HttpServletResponse response,String flag,String url,SimpleDateFormat format) throws IOException{//获取签名随机字符串
GetRandomStr randomStr = new GetRandomStr();
String noncestr = randomStr.getRandomString(15);
//获取签名时间戳
String timestamp = Long.toString(System.currentTimeMillis());
//请求accessToken
String accessTokenUrl ="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wxca57e6589ccebff0&secret=b7d7c5df24644563be32bd84b90c8bf6";
String tokenJson = WeixinUtil.httpRequest(accessTokenUrl, "GET", null);
Gson gson = new Gson();
ShareAccess_Token token = gson.fromJson(tokenJson, ShareAccess_Token.class);
String to= token.getAccess_token();
//获取标签
String urlTicket ="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+to+"&type=jsapi";
String ticketJson = WeixinUtil.httpRequest(urlTicket, "GET", null);
Ticket ticket = gson.fromJson(ticketJson, Ticket.class);
String t = ticket.getTicket();
//String uuid = UUID.randomUUID().toString().trim().replaceAll("-", "");
//我的Ticket ID是写死的 20160114wiimediamrylsong1152
String acquiretime = format.format(new Date());
ticket.setTid("20160114wiimediamrylsong1152");
ticket.setAcquiretime(acquiretime);
ticket.setTimestamp(timestamp);
ticket.setNoncestr(noncestr);/**
* 注意事项
* 1.签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。
* 2.签名用的url必须是调用JS接口页面的完整URL。
* 3.出于安全考虑,开发者必须在服务器端实现签名的逻辑。
*
*根据第1点要求 signature 配置的时候很容易出错,需要把生成 Ticket的 noncestr和 timestamp传给客户端*
*/String signature = signature(t,timestamp,noncestr,url);
System.out.print("ticket: "+t);
SignatureBean signatureBean = new SignatureBean();
signatureBean.setNoncestr(noncestr);
signatureBean.setSignature(signature);
signatureBean.setTimestamp(timestamp);
signatureBean.setUrl(url);
response.setContentType("text/html;charset=UTF-8");
response.getWriter().print(new Gson().toJson(signatureBean));return ticket;
}/**
*
*Project:mryl_phone_v2*
*:mryl_phone_v2*
*Description:根据标签,时间戳,密匙,URL进行签名*
*Company:Wiimedia*
*@Athor:SongJia
*
*@Date:2016-7-15 上午09:37:13
*
*/
private String signature(String jsapi_ticket, String timestamp, String noncestr, String url) {
jsapi_ticket = "jsapi_ticket=" + jsapi_ticket;
timestamp = "timestamp=" + timestamp;
noncestr = "noncestr=" + noncestr;
url = "url=" + url;
String[] arr = new String[] { jsapi_ticket, timestamp, noncestr, url };
// 将token、timestamp、nonce,url参数进行字典序排序
Arrays.sort(arr);
StringBuilder content = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
content.append(arr[i]);
if (i != arr.length - 1) {
content.append("&");
}
}
MessageDigest md = null;
String tmpStr = null;try {
md = MessageDigest.getInstance("SHA-1");
// 将三个参数字符串拼接成一个字符串进行sha1加密
byte[] digest = md.digest(content.toString().getBytes());
tmpStr = byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}content = null;
return tmpStr;
}
/**
* 将字节转换为十六进制字符串
*
* @param mByte
* @return
*/
private static String byteToHexStr(byte mByte) {char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
char[] tempArr = new char[2];
tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
tempArr[1] = Digit[mByte & 0X0F];String s = new String(tempArr);
return s;
}
/**
* 将字节数组转换为十六进制字符串
*
* @param byteArray
* @return
*/
private static String byteToStr(byte[] byteArray) {
String strDigest = "";
for (int i = 0; i < byteArray.length; i++) {
strDigest += byteToHexStr(byteArray[i]);
}
return strDigest;
}class ShareAccess_Token{
private String access_token;
private String expires_in;
public String getAccess_token() {
return access_token;
}
public void setAccess_token(String accessToken) {
access_token = accessToken;
}
public String getExpires_in() {
return expires_in;
}
public void setExpires_in(String expiresIn) {
expires_in = expiresIn;
}}
}

原大神的实现中是将Ticket存入数据库中,但是考虑到TicketId已写死,Ticket只有一条数据,存入数据库,再从数据库中取值新等过于麻烦,故将Ticket作为static变量。第一次访问时创建,超时时给他赋新值。1.2.2weixin.util{CSDN:CODE:2126562
package com.weixin.util;/**
* Created by Administrator on 2017/1/9.
*/
public class SignatureBean {
private String noncestr;
private String url;
private String timestamp;
private String signature;
public String getNoncestr() {
return noncestr;
}
public void setNoncestr(String noncestr) {
this.noncestr = noncestr;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature;
}}
package com.weixin.util;import java.util.Random;/**
* Created by Administrator on 2017/1/9.
* 获取随机字符串
*/public class GetRandomStr {
public String getRandomString(int length) {
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
}

package com.weixin.util;import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;/**
* Created by Administrator on 2017/1/10.
*/
public class MyX509TrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {}@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {}@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
ps.因为大神的注释写的很清楚,拉入我的项目中是可用滴,当然关于这个MyX509TrustManager我也不懂,百度之后还是不知道应该信任哪些证书,然后,干脆什么都没改,信任全部。当然网上也有很多不是通过Https请求的,然而根据微信现在的规定,好像都需要Https请求了。对于这个MyX509TrustManager大家有什么好的实现欢迎指教。1.2.3weixin.model
package com.weixin.model;/**
* Created by Administrator on 2017/1/9.
*/
public class Ticket {
private String tid;
private String ticket;
private String errcode;
private String errmsg;
private String expires_in;
private String acquiretime;
private String noncestr;
private String timestamp;
public Ticket(String tid, String ticket, String errcode, String errmsg,
String expiresIn, String acquiretime, String noncestr,
String timestamp) {
super();
this.tid = tid;
this.ticket = ticket;
this.errcode = errcode;
this.errmsg = errmsg;
expires_in = expiresIn;
this.acquiretime = acquiretime;
this.noncestr = noncestr;
this.timestamp = timestamp;
}
public String getTid() {
return tid;
}
public void setTid(String tid) {
this.tid = tid;
}
public String getTicket() {
return ticket;
}
public void setTicket(String ticket) {
this.ticket = ticket;
}
public String getErrcode() {
return errcode;
}
public void setErrcode(String errcode) {
this.errcode = errcode;
}
public String getErrmsg() {
return errmsg;
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
public String getExpires_in() {
return expires_in;
}
public void setExpires_in(String expiresIn) {
expires_in = expiresIn;
}
public String getAcquiretime() {
return acquiretime;
}
public void setAcquiretime(String acquiretime) {
this.acquiretime = acquiretime;
}
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;
}
}
最后,由于是在项目下新开的包,别忘了在Application.java中加入
@ComponentScan(basePackages = {"com.mzqadmin","com.baidu","com.weixin"})

另外,调试时把debug:true如果debug:ok却始终无法完成定制,一定是你的js代码有问题,后台验证已经通过了,看看你的js代码里参数是否带“”什么的。别问我怎么知道的,低级错误害死人呐~以上,是我做微信分享功能参考和实现的所有代码,有很多不足之处,还希望各位看官不吝赐教。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐