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

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

今天的主人公: 微信 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. mybatisplus打印sql语句

    package com.osplat.config; import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; ...

  2. pl/sql developer 问题总结

    问题1,出现NLS_LANG和字符集(Character set)问题 安装完PL/SQL后打开,遇到如图问题. 原因:这是因为系统没有设置NLS_LANG系统变量. 解决方法:有两种方式查看. 1. ...

  3. Windows Server 2012 R2 双网卡绑定

    双网卡绑定主要有以下两点好处: 1.实现网络容错:主主模式和主被模式 2.带宽聚合 首先准备工作需要两台虚拟机,Server01是目标服务器,需要有两块网卡,并且清空两块网卡的现有配置,Server0 ...

  4. TT-付款方式

    付款方式 一般T/T是可以的,上述客户我们采用的付款方式就是定金加TT,如果是信用证方式,那么需要资信良好的开证行: 中国工商银行 汇丰银行 渣打银行 花旗银行 MUSLIM COMMERCIAL B ...

  5. Rational AppScan 标准版可扩展性和二次开发能力简介

    下载:IBM® Rational® AppScan 标准版  |   Web 应用安全与 IBM Rational AppScan 工具包 获取免费的 Rational 软件工具包系列,下载更多的 R ...

  6. 浅谈spring为什么推荐使用构造器注入

    转载自: https://www.cnblogs.com/joemsu/p/7688307.html 一.前言 ​ Spring框架对Java开发的重要性不言而喻,其核心特性就是IOC(Inversi ...

  7. setTimeout与Promise的区别

    1,4,3,2 Promise是一个micro task  主线程是一个task  micro task queue会在task后面执行 setTimeout返回的函数是一个新的task macro ...

  8. python 修改的函数装饰器

    把好的代码记录下来 方便以后学习 修改的函数参数装饰器 from functools import wraps import time import logging def warn(timeout) ...

  9. linux中du与df的区别和联系

    1,两者区别 du,disk usage,是通过搜索文件来计算每个文件的大小然后累加,du能看到的文件只是一些当前存在 的,没有被删除的.他计算的大小就是当前他认为存在的所有文件大小的累加和. df, ...

  10. vb编程中的is是什么意思??

    在select case 语句中可以使用关系运算符大于>小于<等于=等关系运算符,需要用关键字IS和TO.用个例子来说明:Private Sub Command1_Click()Dim a ...