前面已经学会了微信网页授权,现在微信网页的功能也可以开展起来啦!

首先,我们先来学习一下分享,如何在自己的页面获取分享接口及让小伙伴来分享呢?

今天的主人公: 微信 JS-SDK, 对应官方链接为:微信JS-SDK说明文档

经过分析,要使用微信SJ-SDK需要完成如下工作:

由以上分析,我们需要做服务器的注入验证,另外在需要分享的页面中引入js文件,这样就可以调用微信JS-SDK中的接口啦~

下面首先开始实现注入验证功能,主要分为如下几步:

第一步,获取access_token:

access_token是微信接口号开发的基本数据,建议存到数据库中保存。(第三篇中已实现,可参考)

第二步,获取jsapi_ticket:

由官方文档得知,只需Get方式调用接口:https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi

其中参数为第一步中获取的access_token,调用方法已在工具类中。另jsapi_ticket有效时间为2个小时,且每个页面均需用到接口验证,因此可参考access_token,

将jsapi_ticket 存至数据库,以便后续获取。

获取jsapi_ticket主方法可参考(请忽略注释问题):

     /**
* 获取微信 js-api-ticket
* @return
*/
public JSAPITicket getJsApiTicket()
{ /*
* 第一步,查询数据库中ticket是否已过期 未过期则直接获取
*/
if (updateJSAPITicket())
{
return mJSAPITicket;
} /* 第二步,获取当前有效的access_token */
WeChatTokenService tWeChatTokenService = new WeChatTokenService();
// 此处获取测试账号的
String access_token = tWeChatTokenService.getToken(mAppid, mAppSecret).getToken(); /* 第三步,则通过https调用获取 jsapi_ticket */
if (!getJSApiTicketbyhttps(access_token))
{
System.out.println("获取ticket失败!");
return null;
} return mJSAPITicket;
}

其中jsapi_ticket对应实体类为:

 /**
* 微信 JS-API-Ticket类
* @author Damon
*/
public class JSAPITicket implements Cloneable
{ // 微信 ticket流水号
private String ticketid = ""; // 微信jsapi_ticket
private String ticket = ""; // 有效时间
private int expires_in = 0; // 微信appid
private String appid = ""; // 申请用户密钥
private String appsecret = ""; // 获取时间
private String createtime = ""; public String getTicketid()
{
return ticketid;
} public void setTicketid(String ticketid)
{
this.ticketid = ticketid;
} public String getTicket()
{
return ticket;
} public void setTicket(String ticket)
{
this.ticket = ticket;
} public int getExpires_in()
{
return expires_in;
} public void setExpires_in(int expires_in)
{
this.expires_in = expires_in;
} public String getAppid()
{
return appid;
} public void setAppid(String appid)
{
this.appid = appid;
} public String getCreatetime()
{
return createtime;
} public void setCreatetime(String createtime)
{
this.createtime = createtime;
} public String getAppsecret()
{
return appsecret;
} public void setAppsecret(String appsecret)
{
this.appsecret = appsecret;
} @Override
public JSAPITicket clone() throws CloneNotSupportedException
{
// TODO Auto-generated method stub
JSAPITicket cloneTicket = (JSAPITicket) super.clone();
return cloneTicket;
} }

对应表结构可以参考:

对应的SQL脚本:

 drop table if exists WeChatJSAPITicket;

 /*==============================================================*/
/* Table: WeChatJSAPITicket */
/*==============================================================*/
create table WeChatJSAPITicket
(
ticketid varchar(60) not null,
ticket varchar(300),
expires_in int,
appid varchar(60),
appsecret varchar(60),
createtime timestamp,
primary key (ticketid)
);

主方法调用的明细方法为:

     /**
* 获取微信JS-API-Ticket信息
* @return
*/
private boolean updateJSAPITicket()
{
// 查询数据库数据,如果有则不用更新,无则需要更新
Connection con = null;
PreparedStatement stmt = null;
ResultSet rs = null;
// 判断当前token是否在有效时间内
String sql = " select * from wechatjsapiticket where appid ='" + mAppid + "' and appsecret ='" + mAppSecret
+ "' and ( current_timestamp -createtime) <expires_in order by createTime desc limit 0,1";
System.out.println(sql);
try
{
// 创建数据库链接
con = DBConnPool.getConnection();
// 创建处理器
stmt = con.prepareStatement(sql);
// 查询Token,读取1条记录
rs = stmt.executeQuery();
if (rs.next())
{
mJSAPITicket.setTicketid(rs.getString("ticketid"));
mJSAPITicket.setTicket(rs.getString("ticket"));
mJSAPITicket.setExpires_in(rs.getInt("expires_in"));
mJSAPITicket.setAppid(rs.getString("appid"));
mJSAPITicket.setAppsecret(rs.getString("appsecret"));
}
else
{
System.out.println("未查询到对应ticket");
return false;
}
}
catch (Exception e)
{
// TODO: handle exception
return false;
} return true;
} /**
* 调用请求获取ticket
* @param access_token
* @return
*/
private boolean getJSApiTicketbyhttps(String access_token)
{ String current_time = new Date().getTime() + ""; try
{
// 请求地址
String path = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
path = path.replace("ACCESS_TOKEN", access_token);
String strResp = WeChatUtil.doHttpsGet(path, "");
System.out.println(strResp); // 解析获取的token信息
Map<String, Object> tMap = WeChatUtil.jsonToMap(strResp); System.out.println(tMap.toString()); mJSAPITicket.setTicketid(WeChatUtil.getMaxJSAPITicketID());
mJSAPITicket.setTicket((String) tMap.get("ticket"));
mJSAPITicket.setExpires_in(Integer.parseInt((String) tMap.get("expires_in")));
mJSAPITicket.setAppid(mAppid);
mJSAPITicket.setAppsecret(mAppSecret);
mJSAPITicket.setCreatetime(current_time); System.out.println(mJSAPITicket.getTicket()); }
catch (HttpException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
return false;
} // 存储JS-API-Ticket至数据库
if (!saveJSAPITicket(mJSAPITicket))
{
return false;
} return true;
} /**
* 将获取到的ticket信息存到数据库
* @param tJSAPITicket
* @return
*/
private boolean saveJSAPITicket(JSAPITicket tJSAPITicket)
{
PreparedStatement pst = null;
Connection conn = null;
try
{
JSAPITicket ticket = tJSAPITicket.clone(); System.out.println(ticket.getTicketid() + ticket.getTicket()); conn = DBConnPool.getConnection();
// 创建预处理器
pst = conn.prepareStatement("insert into wechatjsapiticket(ticketid, ticket, expires_in,appid, appsecret,createtime) values (?,?,?,?,?,?)"); pst.setString(1, ticket.getTicketid());
pst.setString(2, ticket.getTicket());
pst.setInt(3, ticket.getExpires_in());
pst.setString(4, ticket.getAppid());
pst.setString(5, ticket.getAppsecret());
long now = new Date().getTime();
pst.setTimestamp(6, new java.sql.Timestamp(Long.parseLong(ticket.getCreatetime())));
pst.execute(); }
catch (CloneNotSupportedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
catch (SQLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
catch (Exception e)
{
// TODO: handle exception
System.out.println("出现额外异常");
return false;
} return true;
}

这样就方便我们获取access_ticket啦!

第三步,实现数据签名:

签名生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。

这里需要用到四个参数,具体分析如下:

参数 说明
noncestr 随机字符串,可用java.util.UUUID类实现
jsapi_ticket 调用前面方法获取
timestamp 当前时间戳
url 传入参数,每次由前端传入

另外,参数加密算法为SHA1加密,因此实现方法为:

     /**
* ticket数据签名
* @return
*/
public WeChatJSAPISign getSignTicket(String requestUrl)
{
// 随机字符串
String noncestr = UUID.randomUUID().toString().replace("-", "");
String jsapi_ticket = getJsApiTicket().getTicket();
long timestamp = new Date().getTime(); String params = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + noncestr + "&timestamp=" + timestamp + "&url="
+ requestUrl;
String signature = ""; System.out.println("params:" + params); try
{
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(params.getBytes("UTF-8"));
signature = WeChatUtil.byteToHex(crypt.digest());
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
} WeChatJSAPISign tChatJSAPISign = new WeChatJSAPISign(); tChatJSAPISign.setAppId(mAppid);
tChatJSAPISign.setNoncestr(noncestr);
tChatJSAPISign.setTimestamp(timestamp);
tChatJSAPISign.setSignature(signature); return tChatJSAPISign;
}

返回定义的参数对象,定义如下:

 /**
* // JS-API-Ticket 签名类
* @author Damon
*/
public class WeChatJSAPISign
{ // JS-API-Ticket appid
private String appId = ""; // JS-API-Ticket 随机字符串
private String noncestr = ""; // JS-API-Ticket 时间
private long timestamp = 0; // JS-API-Ticket 签名
private String signature = ""; public String getAppId()
{
return appId;
} public void setAppId(String appId)
{
this.appId = appId;
} public String getNoncestr()
{
return noncestr;
} public void setNoncestr(String noncestr)
{
this.noncestr = noncestr;
} public long getTimestamp()
{
return timestamp;
} public void setTimestamp(long timestamp)
{
this.timestamp = timestamp;
} public String getSignature()
{
return signature;
} public void setSignature(String signature)
{
this.signature = signature;
} }

到这,注入验证的服务器端功能就完成了。

下面也进行页面的编写和调用验证。

第一步,先写一个分享页面(基本的html页面即可),可参考(由于我的工程默认编码GBK,编码请注意):

 <%@ page language="java" contentType="text/html; charset=GBK"   pageEncoding="GBK"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GBK">
<title>damon's share page</title>
<%@include file="wechat_config.jsp" %>
<script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
<link rel="stylesheet" href="./weui/weui.css"/> <!--
<script src="wechat_config.js"></script>
-->
<script type="text/javascript">
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '${appid}', // 必填,公众号的唯一标识
timestamp: '${timestamp}', // 必填,生成签名的时间戳
nonceStr: '${noncestr}', // 必填,生成签名的随机串
signature: '${signature}',// 必填,签名,见附录1
jsApiList: ['onMenuShareTimeline','onMenuShareQQ','onMenuShareQZone'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
}); wx.ready(function(){ // 分享到朋友圈
wx.onMenuShareTimeline({
title: '玩玩微信公众号Java版之六:微信网页授权', // 分享标题
link: 'http://www.cnblogs.com/cooldamon/p/7219400.html', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: 'http://damonhouse.iok.la/wechat/pic1.jpg' // 分享图标
}); //分享到QQ
wx.onMenuShareQQ({
title: '玩玩微信公众号Java版之六:微信网页授权', // 分享标题
desc: '分享测试', // 分享描述
link: 'http://www.cnblogs.com/cooldamon/p/7219400.html', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl: 'http://damonhouse.iok.la/wechat/pic1.jpg' // 分享图标
}); //分享到QQ空间
wx.onMenuShareQZone({
title: '玩玩微信公众号Java版之六:微信网页授权', // 分享标题
desc: '分享QQ空间测试', // 分享描述
link: 'http://www.cnblogs.com/cooldamon/p/7219400.html', // 分享链接
imgUrl: 'http://damonhouse.iok.la/wechat/pic1.jpg' // 分享图标
}); }); wx.error(function(res){
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
}); function shareMe()
{
//分享到QQ空间
wx.onMenuShareQZone({
title: '玩玩微信公众号Java版之六:微信网页授权', // 分享标题
desc: '分享QQ空间测试', // 分享描述
link: 'http://www.cnblogs.com/cooldamon/p/7219400.html', // 分享链接
imgUrl: 'http://damonhouse.iok.la/wechat/pic1.jpg' // 分享图标
}); } </script>
</head>
<body>
<button class="weui-btn weui-btn_plain-primary" onclick="shareMe();">欢迎分享</button>
</body>
</html>

另外这里对微信接口调用写了一个功能的方法,引入wechat_config.jsp

 <%@page import="com.wechat.pojo.WeChatJSAPISign"%>
<%@page import="com.wechat.bl.WeChatJSAPIService"%>
<%
// 微信js-jdk 配置接口处理
// 第一步,获取参数
%> <% String url = request.getRequestURL().toString();
System.out.println(url);
WeChatJSAPIService tWeChatJSAPIService = new WeChatJSAPIService(); WeChatJSAPISign tWeChatJSAPISign = tWeChatJSAPIService.getSignTicket(url);
System.out.println( tWeChatJSAPISign.getAppId());
System.out.println( tWeChatJSAPISign.getNoncestr());
System.out.println( tWeChatJSAPISign.getTimestamp());
System.out.println( tWeChatJSAPISign.getSignature()); request.setAttribute("appid", tWeChatJSAPISign.getAppId());
request.setAttribute("noncestr", tWeChatJSAPISign.getNoncestr());
request.setAttribute("timestamp", tWeChatJSAPISign.getTimestamp());
request.setAttribute("signature", tWeChatJSAPISign.getSignature()); %>

其中说明:

1、引入http://res.wx.qq.com/open/js/jweixin-1.2.0.j

2、验证接口中请注意参数名称(这里粗心弄错了,导致验证失败),另外验证错误原因可参考官方错误说明:附录5-常见错误及解决方法.

3、对应的接口功能,最终实现在左上角的更多按钮,请参考页面:

4、最终实现效果如下(以分享到qq空间为例):

这里多出了【分享到手机QQ】和【分享到QQ空间】两个按钮,点击【分享到QQ空间】,可看到:

恭喜你,成功做出了自己的分享页面! 继续加油吧~

玩玩微信公众号Java版之七:自定义微信分享的更多相关文章

  1. 玩玩微信公众号Java版之六:微信网页授权

    我们经常会访问一些网站,用微信登录的时候需要用到授权,那么微信网页授权是怎么一回事呢,一起来看看吧!   参考官方文档:https://mp.weixin.qq.com/wiki?t=resource ...

  2. 玩玩微信公众号Java版之四:自定义公众号菜单

    序: 微信公众号基本的菜单很难满足个性化及多功能的实现,那么微信能否实现自定菜单呢,具体的功能又如何去实现么?下面就来学习一下微信自定义公众号菜单吧! 自定义菜单接口可实现多种类型按钮,如下: 1.c ...

  3. 玩玩微信公众号Java版之一:配置微信公众平台服务器信息

    在进行微信公众平台开发前,前先做好准备工作,好了以后,我们可以开始啦!   第一.准备好服务端接口   定义一个http服务接口,主要分为如下几步:   1.创建一个servlet类,用来接收请求: ...

  4. 玩玩微信公众号Java版之准备

    微信自2013年流行起来,现在的发展已经超过了我们的想象,那么对应的公众平台,小程序等都是让人眼前一亮的东西,这里来学习一下微信工作号的对接,实现为Java,希望大家一起学习!   这里大概描述一下所 ...

  5. 玩玩微信公众号Java版之三:access_token及存储access_token

    微信官方参考文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183   基本说明: access_token是 ...

  6. 玩玩微信公众号Java版之五:获取关注用户信息

    在关注者与公众号产生消息交互后,公众号可获得关注者的OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的.对于不同公众号,同一用户的openid不同).公众号可通过本接口来根据Op ...

  7. 玩玩微信公众号Java版之二:接收、处理及返回微信消息

    前面已经配置了微信服务器,那么先开始最简单的接收微信消息吧~   可以用我们的微信号来直接进行测试,下面先看测试效果图:   这是最基本的文本消息的接收.处理及返回,来看看是怎么实现的吧!   首先可 ...

  8. JAVA微信公众号网页开发——生成自定义微信菜单(携带参数)

    官网接口地址:https://developers.weixin.qq.com/doc/offiaccount/Custom_Menus/Creating_Custom-Defined_Menu.ht ...

  9. 微信公众号Java接入demo

    微信公众号Java接入demo 前不久买了一台服务,本来是用来当梯子用的,后来买了一个域名搭了一个博客网站,后来不怎么在上面写博客一直闲着,最近申请了一个微信公众号就想着弄点什么玩玩.周末没事就鼓捣了 ...

随机推荐

  1. flutter ListView简介

    child: new Container( child: new Center( child: ListView( shrinkWrap:true, children: <Widget>[ ...

  2. snmp监控f5

    1.硬盘各分区使用情况 2.pool数量.vs数量 3.cpu使用率 4.内存使用率 5.电源 6.风扇 7.端口状态及流量 8.HA状态(主备情况及HA是否处于建立状态) 9.主备机同步状态

  3. 获取网页title(还有一坑未填)

    def getTitle(self,url): #get title title = 'time out' try: self.res = requests.get(url,timeout=5) so ...

  4. spark 线性回归算法(scala)

    构建Maven项目,托管jar包 数据格式 //0.fp_nid,1.nsr_id,2.gf_id,2.hydm,3.djzclx_dm,4.kydjrq,5.xgrq,6.je,7.se,8.jsh ...

  5. spring boot生成的war包运行时出现java.lang.NullPointerException: null

    最近写了一个数据库同步的程序,见之前的博客,没有用到spring框架来集成,用的时纯Java代码.然后,项目经理要我把程序合到spring boot框架中,因为涉及到多数据源,时间又比较紧,同意我直接 ...

  6. asp.net上传图片到服务器

    ASP.NET的FileUpload控件可用于上传文件到服务器.HoverTreeTop新增了一个“阅图”功能,图片就是用FileUpload上传的.阅图功能查看:http://hovertree.c ...

  7. Mac使用Charles进行HTTPS抓包

    技术来源: PengYunjing 第一步 配置HTTP代理,这步与抓取HTTP请求是一样的: 选择在8888端口上监听,然后确定.够选了SOCKS proxy,还能截获到浏览器的http访问请求. ...

  8. github删除

    https://blog.csdn.net/weixin_42152081/article/details/80635777

  9. Unique Letter String LT828

    A character is unique in string S if it occurs exactly once in it. For example, in string S = " ...

  10. java8 学习记录

    一.  lambda表达式 参考 https://www.cnblogs.com/franson-2016/p/5593080.html package com.mytest.java8; impor ...