java开发微信分享到朋友圈功能
微信分享功能开发
用了一天时间,把微信发送给朋友和分享到朋友圈功能开发出来,在这里给大家分享一下,避免大家走弯路。
一、服务器端程序
packagecom.wiimedia.controller;
importjava.io.IOException;
importjava.security.MessageDigest;
importjava.security.NoSuchAlgorithmException;
importjava.text.ParseException;
importjava.text.SimpleDateFormat;
importjava.util.Arrays;
importjava.util.Date;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.RequestMapping;
importcom.google.gson.Gson;
importcom.wiimedia.model.Ticket;
importcom.wiimedia.service.ArticleSolrService;
importcom.wiimedia.service.TicketRepository;
importcom.wiimedia.service.TicketRepositorySolr;
importcom.wiimedia.utils.GetRandomStr;
importcom.wiimedia.utils.SignatureBean;
importcom.wiimedia.utils.weixin.WeixinUtil;
/**
*
*
*<p>Project:mryl_phone_v2</p>
*
*<p>Package:com.wiimedia.controller</p>
*
*<p>Description:微信分享Controller</p>
*
*<p>Company:Wiimedia</p>
*
*@Athor:SongJia
*
*@Date:2016-7-15上午09:34:10
*
*/
@Controller
@RequestMapping("/WeixinshareController/Api/Inteface")
publicclassWeixinshareController{
@Autowired
privateTicketRepositorySolrticketRepositorySolr;
@RequestMapping("/getSignature")
publicStringgetSignature(HttpServletRequestrequest,
HttpServletResponseresponse)throwsIOException,ParseException{
//获取签名页面链接
Stringurl=request.getParameter("url");
SimpleDateFormatformat=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");
//从数据库中获取标签,并检查标签是否过期
Ticketoldticket=ticketRepositorySolr.getTicketById("20160114wiimediamrylsong1152");
if(oldticket==null){//第一次访问,标签不存在。
executeTicket(response,"1",url,format);
returnnull;
}else{//标签存在,判断标签是否超时
StringoldAcquiretime=oldticket.getAcquiretime();
longdifference=format.parse(format.format(newDate())).getTime()-format.parse(oldAcquiretime).getTime();
if(difference>7100000){//标签超时,重新到微信服务器请求标签超时时间为7200秒(7200000毫秒)
executeTicket(response,"2",url,format);
returnnull;
}else{//标签未超时
/**
*注意事项
*1.签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。
*2.签名用的url必须是调用JS接口页面的完整URL。
*3.出于安全考虑,开发者必须在服务器端实现签名的逻辑。
*
****根据第1点要求signature配置的时候很容易出错,需要把生成Ticket的noncestr和timestamp传给客户端***
*/
Stringsignature=signature(oldticket.getTicket(),oldticket.getTimestamp(),oldticket.getNoncestr(),url);
SignatureBeansignatureBean=newSignatureBean();
signatureBean.setNoncestr(oldticket.getNoncestr());
signatureBean.setSignature(signature);
signatureBean.setTimestamp(oldticket.getTimestamp());
signatureBean.setUrl(url);
response.setContentType("text/html;charset=UTF-8");
response.getWriter().print(newGson().toJson(signatureBean));
returnnull;
}
}
}
/**
*
*<p>Project:mryl_phone_v2</p>
*
*<p>:mryl_phone_v2</p>
*
*<p>Description:更新和获取ticket的方法,因为用的solr所以更新和新增是一样的ID无则添加,有责更新</p>
*
*<p>Company:Wiimedia</p>
*
*@Athor:SongJia
*
*@Date:2016-7-15上午09:45:00
*
*/
publicvoidexecuteTicket(HttpServletResponseresponse,Stringflag,Stringurl,SimpleDateFormatformat)throwsIOException{
//获取签名随即字符串
GetRandomStrrandomStr=newGetRandomStr();
Stringnoncestr=randomStr.getRandomString(15);
//获取签名时间戳
Stringtimestamp=Long.toString(System.currentTimeMillis());
//请求accessToken
StringaccessTokenUrl="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=您的APPID&secret=您的密匙";
StringtokenJson=WeixinUtil.httpRequest(accessTokenUrl,"GET",null);
Gsongson=newGson();
ShareAccess_Tokentoken=gson.fromJson(tokenJson,ShareAccess_Token.class);
Stringto=token.getAccess_token();
//获取标签
StringurlTicket="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+to+"&type=jsapi";
StringticketJson=WeixinUtil.httpRequest(urlTicket,"GET",null);
Ticketticket=gson.fromJson(ticketJson,Ticket.class);
Stringt=ticket.getTicket();
//Stringuuid=UUID.randomUUID().toString().trim().replaceAll("-","");
//我的TicketID是写死的
Stringacquiretime=format.format(newDate());
ticket.setTid("20160114wiimediamrylsong1152");
ticket.setAcquiretime(acquiretime);
ticket.setTimestamp(timestamp);
ticket.setNoncestr(noncestr);
//因为用的SOLR所以更新和添加的方法是一样的,可以根据自己具体需求进行修改,本文不再贴出代码.
if(flag.equals("2")){
ticketRepositorySolr.addTicketToSolr(ticket);
}else{
ticketRepositorySolr.addTicketToSolr(ticket);
}
/**
*注意事项
*1.签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。
*2.签名用的url必须是调用JS接口页面的完整URL。
*3.出于安全考虑,开发者必须在服务器端实现签名的逻辑。
*
*根据第1点要求signature配置的时候很容易出错,需要把生成Ticket的noncestr和timestamp传给客户端*
*/
Stringsignature=signature(t,timestamp,noncestr,url);
SignatureBeansignatureBean=newSignatureBean();
signatureBean.setNoncestr(noncestr);
signatureBean.setSignature(signature);
signatureBean.setTimestamp(timestamp);
signatureBean.setUrl(url);
response.setContentType("text/html;charset=UTF-8");
response.getWriter().print(newGson().toJson(signatureBean));
}
/**
*
*<p>Project:mryl_phone_v2</p>
*
*<p>:mryl_phone_v2</p>
*
*<p>Description:根据标签,时间戳,密匙,URL进行签名</p>
*
*<p>Company:Wiimedia</p>
*
*@Athor:SongJia
*
*@Date:2016-7-15上午09:37:13
*
*/
privateStringsignature(Stringjsapi_ticket,Stringtimestamp,Stringnoncestr,Stringurl){
jsapi_ticket="jsapi_ticket="+jsapi_ticket;
timestamp="timestamp="+timestamp;
noncestr="noncestr="+noncestr;
url="url="+url;
String[]arr=newString[]{jsapi_ticket,timestamp,noncestr,url};
//将token、timestamp、nonce,url参数进行字典序排序
Arrays.sort(arr);
StringBuildercontent=newStringBuilder();
for(inti=0;i<arr.length;i++){
content.append(arr[i]);
if(i!=arr.length-1){
content.append("&");
}
}
MessageDigestmd=null;
StringtmpStr=null;
try{
md=MessageDigest.getInstance("SHA-1");
//将三个参数字符串拼接成一个字符串进行sha1加密
byte[]digest=md.digest(content.toString().getBytes());
tmpStr=byteToStr(digest);
}catch(NoSuchAlgorithmExceptione){
e.printStackTrace();
}
content=null;
returntmpStr;
}
/**
*将字节转换为十六进制字符串
*
*@parammByte
*@return
*/
privatestaticStringbyteToHexStr(bytemByte){
char[]Digit={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char[]tempArr=newchar[2];
tempArr[0]=Digit[(mByte>>>4)&0X0F];
tempArr[1]=Digit[mByte&0X0F];
Strings=newString(tempArr);
returns;
}
/**
*将字节数组转换为十六进制字符串
*
*@parambyteArray
*@return
*/
privatestaticStringbyteToStr(byte[]byteArray){
StringstrDigest="";
for(inti=0;i<byteArray.length;i++){
strDigest+=byteToHexStr(byteArray[i]);
}
returnstrDigest;
}
classShareAccess_Token{
privateStringaccess_token;
privateStringexpires_in;
publicStringgetAccess_token(){
returnaccess_token;
}
publicvoidsetAccess_token(StringaccessToken){
access_token=accessToken;
}
publicStringgetExpires_in(){
returnexpires_in;
}
publicvoidsetExpires_in(StringexpiresIn){
expires_in=expiresIn;
}
}
}
二、客户端代码.
<scripttype="text/javascript">
varurl=window.location.href;
vararticleId="";
varshareTitle="明日医疗资讯";
varshareImgUrl="";
varuserinfo=localStorage.getItem("_userinfo");
vartimestamp;
varnoncestr;
varsignature;
//获取签名
$.ajax({
type:"GET",
url:"WeixinshareController/Api/Inteface/getSignature",
//data:{timestamp:timestamp,noncestr:noncestr,url:url},
data:{url:url},
success:function(data){
varobjData=JSON.parse(data);
timestamp=objData.timestamp;
noncestr=objData.noncestr;
signature=objData.signature;
console.log(objData);
wxShare();
}
});
functionwxShare(){
wx.config({
debug:false,//开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId:'您的appid',//和获取Ticke的必须一样------必填,公众号的唯一标识
timestamp:timestamp,//必填,生成签名的时间戳
nonceStr:noncestr,//必填,生成签名的随机串
signature:signature,//必填,签名,见附录1
jsApiList:[
'onMenuShareAppMessage'
]//必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
}
wx.ready(function(){
//config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,
//config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关
//接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
//----------“分享给朋友”
wx.onMenuShareAppMessage({
title:"明日医疗资讯",//分享标题
desc:shareTitle,//分享描述
link:url,//分享链接
imgUrl:shareImgUrl,//分享图标
type:'',//分享类型,music、video或link,不填默认为link
dataUrl:'',//如果type是music或video,则要提供数据链接,默认为空
success:function(){
//用户确认分享后执行的回调函数、
},
cancel:function(){
//用户取消分享后执行的回调函数
}
});
//------------"分享到朋友圈"
wx.onMenuShareTimeline({
title:'明日医疗资讯',//分享标题
link:'',//分享链接
imgUrl:shareImgUrl,//分享图标
success:function(){
//用户确认分享后执行的回调函数
},
cancel:function(){
//用户取消分享后执行的回调函数
}
});
//-------------分享到QQ
wx.onMenuShareQQ({
title:'明日医疗资讯',//分享标题
desc:shareTitle,//分享描述
link:'',//分享链接
imgUrl:shareImgUrl,//分享图标
success:function(){
//用户确认分享后执行的回调函数
},
cancel:function(){
//用户取消分享后执行的回调函数
}
});
//-------------分享到QQ空间
wx.onMenuShareQZone({
title:'明日医疗资讯',//分享标题
desc:shareTitle,//分享描述
link:'',//分享链接
imgUrl:shareImgUrl,//分享图标
success:function(){
//用户确认分享后执行的回调函数
},
cancel:function(){
//用户取消分享后执行的回调函数
}
});
});
三、服务器需要的工具类和Model
①Ticket
packagecom.wiimedia.model;
publicclassTicket{
privateStringtid;
privateStringticket;
privateStringerrcode;
privateStringerrmsg;
privateStringexpires_in;
privateStringacquiretime;
privateStringnoncestr;
privateStringtimestamp;
publicTicket(Stringtid,Stringticket,Stringerrcode,Stringerrmsg,
StringexpiresIn,Stringacquiretime,Stringnoncestr,
Stringtimestamp){
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;
}
publicStringgetTid(){
returntid;
}
publicvoidsetTid(Stringtid){
this.tid=tid;
}
publicStringgetTicket(){
returnticket;
}
publicvoidsetTicket(Stringticket){
this.ticket=ticket;
}
publicStringgetErrcode(){
returnerrcode;
}
publicvoidsetErrcode(Stringerrcode){
this.errcode=errcode;
}
publicStringgetErrmsg(){
returnerrmsg;
}
publicvoidsetErrmsg(Stringerrmsg){
this.errmsg=errmsg;
}
publicStringgetExpires_in(){
returnexpires_in;
}
publicvoidsetExpires_in(StringexpiresIn){
expires_in=expiresIn;
}
publicStringgetAcquiretime(){
returnacquiretime;
}
publicvoidsetAcquiretime(Stringacquiretime){
this.acquiretime=acquiretime;
}
publicStringgetNoncestr(){
returnnoncestr;
}
publicvoidsetNoncestr(Stringnoncestr){
this.noncestr=noncestr;
}
publicStringgetTimestamp(){
returntimestamp;
}
publicvoidsetTimestamp(Stringtimestamp){
this.timestamp=timestamp;
}
}
②添加到数据库的业务根据自己需要进行实现.
③GetRandomStr
packagecom.wiimedia.utils;
importjava.util.Random;
publicclassGetRandomStr{
/**
*
*<p>Project:mryl_phone_v2</p>
*
*<p>:mryl_phone_v2</p>
*
*<p>Description:生成随即字符串</p>
*
*<p>Company:Wiimedia</p>
*
*@Athor:SongJia
*
*@Date:2016-7-14上午11:14:46
*
*/
publicStringgetRandomString(intlength){
Stringbase="abcdefghijklmnopqrstuvwxyz0123456789";
Randomrandom=newRandom();
StringBuffersb=newStringBuffer();
for(inti=0;i<length;i++){
intnumber=random.nextInt(base.length());
sb.append(base.charAt(number));
}
returnsb.toString();
}
}
④SignatureBean
packagecom.wiimedia.utils;
publicclassSignatureBean{
privateStringnoncestr;
privateStringurl;
privateStringtimestamp;
privateStringsignature;
publicStringgetNoncestr(){
returnnoncestr;
}
publicvoidsetNoncestr(Stringnoncestr){
this.noncestr=noncestr;
}
publicStringgetUrl(){
returnurl;
}
publicvoidsetUrl(Stringurl){
this.url=url;
}
publicStringgetTimestamp(){
returntimestamp;
}
publicvoidsetTimestamp(Stringtimestamp){
this.timestamp=timestamp;
}
publicStringgetSignature(){
returnsignature;
}
publicvoidsetSignature(Stringsignature){
this.signature=signature;
}
}
⑤WeixinUtil
packagecom.wiimedia.utils.weixin;
importjava.io.BufferedReader;
importjava.io.InputStream;
importjava.io.InputStreamReader;
importjava.io.OutputStream;
importjava.net.ConnectException;
importjava.net.URL;
importjavax.net.ssl.HttpsURLConnection;
importjavax.net.ssl.SSLContext;
importjavax.net.ssl.SSLSocketFactory;
importjavax.net.ssl.TrustManager;
/**
*
*<p>Project:mryl_phone_v2</p>
*
*<p>:mryl_phone_v2</p>
*
*<p>Description:公众平台接口工具类</p>
*
*<p>Company:Wiimedia</p>
*
*@Athor:SongJia
*
*@Date:2016-7-15上午09:37:13
*
*/
publicclassWeixinUtil{
/**
*发起https请求并获取结果
*
*@paramrequestUrl请求地址
*@paramrequestMethod请求方式(GET、POST)
*@paramoutputStr提交的数据
*@returnJSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
*/
publicstaticStringhttpRequest(StringrequestUrl,StringrequestMethod,StringoutputStr){
StringBufferbuffer=newStringBuffer();
try{
//创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[]tm={newMyX509TrustManager()};
SSLContextsslContext=SSLContext.getInstance("SSL","SunJSSE");
sslContext.init(null,tm,newjava.security.SecureRandom());
//从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactoryssf=sslContext.getSocketFactory();
URLurl=newURL(requestUrl);
HttpsURLConnectionhttpUrlConn=(HttpsURLConnection)url.openConnection();
httpUrlConn.setSSLSocketFactory(ssf);
httpUrlConn.setDoOutput(true);
httpUrlConn.setDoInput(true);
httpUrlConn.setUseCaches(false);
//设置请求方式(GET/POST)
httpUrlConn.setRequestMethod(requestMethod);
if("GET".equalsIgnoreCase(requestMethod))
httpUrlConn.connect();
//当有数据需要提交时
if(null!=outputStr){
OutputStreamoutputStream=httpUrlConn.getOutputStream();
//注意编码格式,防止中文乱码
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
//将返回的输入流转换成字符串
InputStreaminputStream=httpUrlConn.getInputStream();
InputStreamReaderinputStreamReader=newInputStreamReader(inputStream,"utf-8");
BufferedReaderbufferedReader=newBufferedReader(inputStreamReader);
Stringstr=null;
while((str=bufferedReader.readLine())!=null){
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
//释放资源
inputStream.close();
inputStream=null;
httpUrlConn.disconnect();
returnbuffer.toString();
}catch(ConnectExceptionce){
ce.printStackTrace();
}catch(Exceptione){
e.printStackTrace();
}
return"";
}
}
四、至此,分享功能已经开发完成,但是,在生成signature的时候会遇到很多问题,这里提供一些wx.config失败的排错方法。
①确认自己的生成的signature是否正确
在微信提供的http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign进行校验
②wx.config中使用的noncestr,timestamp与用以签名中的对应noncestr,timestamp是否一致一致…如上面(一.服务器代码)
(有可能因为JS页面加载顺序问题,服务器生成的signature,noncestr,timestamp在wx.config中没有获取到)。
③确认url是页面完整的url,包括GET参数部分
需要去掉#后面的部分
④config中的appid与用来获取jsapi_ticket的appid是否一致
⑤报错{errmsg:config:ok}是debug的正常返回把调试模式关掉就OK
wx.configdebug:false,
本文已被整理到了《Android微信开发教程汇总》,《java微信开发教程汇总》欢迎大家学习阅读。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。