自定义微信分享"/>
java 自定义微信分享
前面已经学会了微信网页授权,现在微信网页的功能也可以开展起来啦!
首先,我们先来学习一下分享,如何在自己的页面获取分享接口及让小伙伴来分享呢?
今天的主人公: 微信 JS-SDK, 对应官方链接为:微信JS-SDK说明文档
经过分析,要使用微信SJ-SDK需要完成如下工作:
由以上分析,我们需要做服务器的注入验证,另外在需要分享的页面中引入js文件,这样就可以调用微信JS-SDK中的接口啦~
下面首先开始实现注入验证功能,主要分为如下几步:
第一步,获取access_token:
access_token是微信接口号开发的基本数据,建议存到数据库中保存。(第三篇中已实现,可参考)
第二步,获取jsapi_ticket:
由官方文档得知,只需Get方式调用接口:=ACCESS_TOKEN&type=jsapi
其中参数为第一步中获取的access_token,调用方法已在工具类中。另jsapi_ticket有效时间为2个小时,且每个页面均需用到接口验证,因此可参考access_token,
将jsapi_ticket 存至数据库,以便后续获取。
获取jsapi_ticket主方法可参考(请忽略注释问题):
1 /**
2 * 获取微信 js-api-ticket3 *@return
4 */
5 publicJSAPITicket getJsApiTicket()6 {7
8 /*
9 * 第一步,查询数据库中ticket是否已过期 未过期则直接获取10 */
11 if(updateJSAPITicket())12 {13 returnmJSAPITicket;14 }15
16 /*第二步,获取当前有效的access_token*/
17 WeChatTokenService tWeChatTokenService = newWeChatTokenService();18 //此处获取测试账号的
19 String access_token =tWeChatTokenService.getToken(mAppid, mAppSecret).getToken();20
21 /*第三步,则通过https调用获取 jsapi_ticket*/
22 if (!getJSApiTicketbyhttps(access_token))23 {24 System.out.println("获取ticket失败!");25 return null;26 }27
28 returnmJSAPITicket;29 }
View Code
其中jsapi_ticket对应实体类为:
1 /**
2 * 微信 JS-API-Ticket类3 *@authorDamon4 */
5 public class JSAPITicket implementsCloneable6 {7
8 //微信 ticket流水号
9 private String ticketid = "";10
11 //微信jsapi_ticket
12 private String ticket = "";13
14 //有效时间
15 private int expires_in = 0;16
17 //微信appid
18 private String appid = "";19
20 //申请用户密钥
21 private String appsecret = "";22
23 //获取时间
24 private String createtime = "";25
26 publicString getTicketid()27 {28 returnticketid;29 }30
31 public voidsetTicketid(String ticketid)32 {33 this.ticketid =ticketid;34 }35
36 publicString getTicket()37 {38 returnticket;39 }40
41 public voidsetTicket(String ticket)42 {43 this.ticket =ticket;44 }45
46 public intgetExpires_in()47 {48 returnexpires_in;49 }50
51 public void setExpires_in(intexpires_in)52 {53 this.expires_in =expires_in;54 }55
56 publicString getAppid()57 {58 returnappid;59 }60
61 public voidsetAppid(String appid)62 {63 this.appid =appid;64 }65
66 publicString getCreatetime()67 {68 returncreatetime;69 }70
71 public voidsetCreatetime(String createtime)72 {73 this.createtime =createtime;74 }75
76 publicString getAppsecret()77 {78 returnappsecret;79 }80
81 public voidsetAppsecret(String appsecret)82 {83 this.appsecret =appsecret;84 }85
86 @Override87 public JSAPITicket clone() throwsCloneNotSupportedException88 {89 //TODO Auto-generated method stub
90 JSAPITicket cloneTicket = (JSAPITicket) super.clone();91 returncloneTicket;92 }93
94 }
View Code
对应表结构可以参考:
对应的SQL脚本:
1 drop table if existsWeChatJSAPITicket;2
3 /*==============================================================*/
4 /*Table: WeChatJSAPITicket*/
5 /*==============================================================*/
6 create tableWeChatJSAPITicket7 (8 ticketid varchar(60) not null,9 ticket varchar(300),10 expires_in int,11 appid varchar(60),12 appsecret varchar(60),13 createtime timestamp,14 primary key(ticketid)15 );
View Code
主方法调用的明细方法为:
1 /**
2 * 获取微信JS-API-Ticket信息3 *@return
4 */
5 private booleanupdateJSAPITicket()6 {7 //查询数据库数据,如果有则不用更新,无则需要更新
8 Connection con = null;9 PreparedStatement stmt = null;10 ResultSet rs = null;11 //判断当前token是否在有效时间内
12 String sql = " select * from wechatjsapiticket where appid ='" + mAppid + "' and appsecret ='" +mAppSecret13 + "' and ( current_timestamp -createtime)
16 {17 //创建数据库链接
18 con =DBConnPool.getConnection();19 //创建处理器
20 stmt =con.prepareStatement(sql);21 //查询Token,读取1条记录
22 rs =stmt.executeQuery();23 if(rs.next())24 {25 mJSAPITicket.setTicketid(rs.getString("ticketid"));26 mJSAPITicket.setTicket(rs.getString("ticket"));27 mJSAPITicket.setExpires_in(rs.getInt("expires_in"));28 mJSAPITicket.setAppid(rs.getString("appid"));29 mJSAPITicket.setAppsecret(rs.getString("appsecret"));30 }31 else
32 {33 System.out.println("未查询到对应ticket");34 return false;35 }36 }37 catch(Exception e)38 {39 //TODO: handle exception
40 return false;41 }42
43
44 return true;45 }46
47
48 /**
49 * 调用请求获取ticket50 *@paramaccess_token51 *@return
52 */
53 private booleangetJSApiTicketbyhttps(String access_token)54 {55
56 String current_time = new Date().getTime() + "";57
58 try
59 {60 //请求地址
61 String path = "=ACCESS_TOKEN&type=jsapi";62 path = path.replace("ACCESS_TOKEN", access_token);63 String strResp = WeChatUtil.doHttpsGet(path, "");64 System.out.println(strResp);65
66 //解析获取的token信息
67 Map tMap =WeChatUtil.jsonToMap(strResp);68
69 System.out.println(tMap.toString());70
71 mJSAPITicket.setTicketid(WeChatUtil.getMaxJSAPITicketID());72 mJSAPITicket.setTicket((String) tMap.get("ticket"));73 mJSAPITicket.setExpires_in(Integer.parseInt((String) tMap.get("expires_in")));74 mJSAPITicket.setAppid(mAppid);75 mJSAPITicket.setAppsecret(mAppSecret);76 mJSAPITicket.setCreatetime(current_time);77
78 System.out.println(mJSAPITicket.getTicket());79
80 }81 catch(HttpException e)82 {83 //TODO Auto-generated catch block
84 e.printStackTrace();85 return false;86 }87 catch(IOException e)88 {89 //TODO Auto-generated catch block
90 e.printStackTrace();91 return false;92 }93
94 //存储JS-API-Ticket至数据库
95 if (!saveJSAPITicket(mJSAPITicket))96 {97 return false;98 }99
100 return true;101 }102
103 /**
104 * 将获取到的ticket信息存到数据库105 *@paramtJSAPITicket106 *@return
107 */
108 private booleansaveJSAPITicket(JSAPITicket tJSAPITicket)109 {110 PreparedStatement pst = null;111 Connection conn = null;112 try
113 {114 JSAPITicket ticket =tJSAPITicket.clone();115
116 System.out.println(ticket.getTicketid() +ticket.getTicket());117
118 conn =DBConnPool.getConnection();119 //创建预处理器
120 pst = conn.prepareStatement("insert into wechatjsapiticket(ticketid, ticket, expires_in,appid, appsecret,createtime) values (?,?,?,?,?,?)");121
122 pst.setString(1, ticket.getTicketid());123 pst.setString(2, ticket.getTicket());124 pst.setInt(3, ticket.getExpires_in());125 pst.setString(4, ticket.getAppid());126 pst.setString(5, ticket.getAppsecret());127 long now = newDate().getTime();128 pst.setTimestamp(6, newjava.sql.Timestamp(Long.parseLong(ticket.getCreatetime())));129 pst.execute();130
131 }132 catch(CloneNotSupportedException e)133 {134 //TODO Auto-generated catch block
135 e.printStackTrace();136 return false;137 }138 catch(SQLException e)139 {140 //TODO Auto-generated catch block
141 e.printStackTrace();142 return false;143 }144 catch(Exception e)145 {146 //TODO: handle exception
147 System.out.println("出现额外异常");148 return false;149 }150
151 return true;152 }
View Code
这样就方便我们获取access_ticket啦!
第三步,实现数据签名:
签名生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。
这里需要用到四个参数,具体分析如下:
参数
说明
noncestr
随机字符串,可用java.util.UUUID类实现
jsapi_ticket
调用前面方法获取
timestamp
当前时间戳
url
传入参数,每次由前端传入
另外,参数加密算法为SHA1加密,因此实现方法为:
1 /**
2 * ticket数据签名3 *@return
4 */
5 publicWeChatJSAPISign getSignTicket(String requestUrl)6 {7 //随机字符串
8 String noncestr = UUID.randomUUID().toString().replace("-", "");9 String jsapi_ticket =getJsApiTicket().getTicket();10 long timestamp = newDate().getTime();11
12 String params = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + noncestr + "×tamp=" + timestamp + "&url="
13 +requestUrl;14 String signature = "";15
16 System.out.println("params:" +params);17
18 try
19 {20 MessageDigest crypt = MessageDigest.getInstance("SHA-1");21 crypt.reset();22 crypt.update(params.getBytes("UTF-8"));23 signature =WeChatUtil.byteToHex(crypt.digest());24 }25 catch(NoSuchAlgorithmException e)26 {27 e.printStackTrace();28 }29 catch(UnsupportedEncodingException e)30 {31 e.printStackTrace();32 }33
34 WeChatJSAPISign tChatJSAPISign = newWeChatJSAPISign();35
36 tChatJSAPISign.setAppId(mAppid);37 tChatJSAPISign.setNoncestr(noncestr);38 tChatJSAPISign.setTimestamp(timestamp);39 tChatJSAPISign.setSignature(signature);40
41 returntChatJSAPISign;42 }
View Code
返回定义的参数对象,定义如下:
1 /**
2 * // JS-API-Ticket 签名类3 *@authorDamon4 */
5 public classWeChatJSAPISign6 {7
8 //JS-API-Ticket appid
9 private String appId = "";10
11 //JS-API-Ticket 随机字符串
12 private String noncestr = "";13
14 //JS-API-Ticket 时间
15 private long timestamp = 0;16
17 //JS-API-Ticket 签名
18 private String signature = "";19
20 publicString getAppId()21 {22 returnappId;23 }24
25 public voidsetAppId(String appId)26 {27 this.appId =appId;28 }29
30 publicString getNoncestr()31 {32 returnnoncestr;33 }34
35 public voidsetNoncestr(String noncestr)36 {37 this.noncestr =noncestr;38 }39
40 public longgetTimestamp()41 {42 returntimestamp;43 }44
45 public void setTimestamp(longtimestamp)46 {47 this.timestamp =timestamp;48 }49
50 publicString getSignature()51 {52 returnsignature;53 }54
55 public voidsetSignature(String signature)56 {57 this.signature =signature;58 }59
60 }
View Code
到这,注入验证的服务器端功能就完成了。
下面也进行页面的编写和调用验证。
第一步,先写一个分享页面(基本的html页面即可),可参考(由于我的工程默认编码GBK,编码请注意):
1
2
3
4
5
6
damon's share page7
8
9
10
11
14
15 wx.config({16 debug:false,//开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
17 appId:'${appid}',//必填,公众号的唯一标识
18 timestamp:'${timestamp}',//必填,生成签名的时间戳
19 nonceStr:'${noncestr}',//必填,生成签名的随机串
20 signature:'${signature}',//必填,签名,见附录1
21 jsApiList: ['onMenuShareTimeline','onMenuShareQQ','onMenuShareQZone']//必填,需要使用的JS接口列表,所有JS接口列表见附录2
22 });23
24 wx.ready(function(){25
26 //分享到朋友圈
27 wx.onMenuShareTimeline({28 title:'玩玩微信公众号Java版之六:微信网页授权',//分享标题
29 link:'.html',//分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
30 imgUrl:'.jpg' //分享图标
31 });32
33 //分享到QQ
34 wx.onMenuShareQQ({35 title:'玩玩微信公众号Java版之六:微信网页授权',//分享标题
36 desc:'分享测试',//分享描述
37 link:'.html',//分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
38 imgUrl:'.jpg' //分享图标
39 });40
41 //分享到QQ空间
42 wx.onMenuShareQZone({43 title:'玩玩微信公众号Java版之六:微信网页授权',//分享标题
44 desc:'分享QQ空间测试',//分享描述
45 link:'.html',//分享链接
46 imgUrl:'.jpg' //分享图标
47 });48
49
50 });51
52 wx.error(function(res){53 //config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
54 });55
56 functionshareMe()57 {58 //分享到QQ空间
59 wx.onMenuShareQZone({60 title:'玩玩微信公众号Java版之六:微信网页授权',//分享标题
61 desc:'分享QQ空间测试',//分享描述
62 link:'.html',//分享链接
63 imgUrl:'.jpg' //分享图标
64 });65
66 }67
68
69
70
71 欢迎分享
72
73
View Code
另外这里对微信接口调用写了一个功能的方法,引入wechat_config.jsp
1
2
3
4 //微信js-jdk 配置接口处理5 //第一步,获取参数6 %>
7
8
9
10 Stringurl=request.getRequestURL().toString();11 System.out.println(url);12 WeChatJSAPIService tWeChatJSAPIService= newWeChatJSAPIService();13
14 WeChatJSAPISign tWeChatJSAPISign=tWeChatJSAPIService.getSignTicket(url);15 System.out.println( tWeChatJSAPISign.getAppId());16 System.out.println( tWeChatJSAPISign.getNoncestr());17 System.out.println( tWeChatJSAPISign.getTimestamp());18 System.out.println( tWeChatJSAPISign.getSignature());19
20 request.setAttribute("appid", tWeChatJSAPISign.getAppId());21 request.setAttribute("noncestr", tWeChatJSAPISign.getNoncestr());22 request.setAttribute("timestamp", tWeChatJSAPISign.getTimestamp());23 request.setAttribute("signature", tWeChatJSAPISign.getSignature());24
25 %>
View Code
其中说明:
1、引入.2.0.j
2、验证接口中请注意参数名称(这里粗心弄错了,导致验证失败),另外验证错误原因可参考官方错误说明:附录5-常见错误及解决方法.
3、对应的接口功能,最终实现在左上角的更多按钮,请参考页面:
4、最终实现效果如下(以分享到qq空间为例):
这里多出了【分享到手机QQ】和【分享到QQ空间】两个按钮,点击【分享到QQ空间】,可看到:
恭喜你,成功做出了自己的分享页面! 继续加油吧~
更多推荐
java 自定义微信分享
发布评论