这个给大家分享一下微信JS-SDK的基本使用,经过一天时间的研究终于可以顺利把JS-SDK连接成功了。下面就跟大家一起分享一下我的方法,当然我也是参照其他的大神来写的。
首先,建立一个servlet命名未HttpUtil
package com.source.weixin.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.UUID;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import com.source.weixin.thread.TokenThread;
import com.source.weixin.util.WeixinUtil;
public class HttpUtil extends HttpServlet {
/**
* Constructor of the object.
*/
public HttpUtil() {
super();
}
/**
* Destruction of the servlet.
*/
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}
/**
* The doGet method of the servlet.
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long time = System.currentTimeMillis()/1000;
String randomStr = UUID.randomUUID().toString();
//特别注意的是调用微信js,url必须是当前页面(转发的不行)
String str = "jsapi_ticket="+TokenThread.jsapi_ticket+"&noncestr="+randomStr+"×tamp="+time+"&url=http://foreverxhj.duapp.com/HttpUtil";
String signature = WeixinUtil.sha1Encrypt(str);
RequestDispatcher rd =request.getRequestDispatcher("demo.jsp");
String accerssToken =TokenThread.accessToken.getToken();
String jsApiTicket =TokenThread.jsapi_ticket;
request.setAttribute("time", time);
request.setAttribute("randomStr", randomStr);
request.setAttribute("signature", signature);
request.setAttribute("accessToken", accerssToken);
request.setAttribute("jsapi_ticket", jsApiTicket);
rd.forward(request, response);
}
/**
* The doPost method of the servlet.
*
* This method is called when a form has its tag value method equals to post.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("");
out.println("");
out.println(" A Servlet ");
out.println(" ");
out.print(" This is ");
out.print(this.getClass());
out.println(", using the POST method");
out.println(" ");
out.println("");
out.flush();
out.close();
}
/**
* Initialization of the servlet.
*
* @throws ServletException if an error occurs
*/
public void init() throws ServletException {
// Put your code here
}
}
这里参考了柳峰老师的方法,写一个线程ThokenThread。 默认初始化调用来存储AccessToken和JSApi_Ticket。线程有效时间为7000秒。由于官方的有效时间为7200秒,而且每天的请求次数有一定的限制,所以设置成7000秒比较合适点。
下面是TokenThread类的代码:
package com.source.weixin.thread;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.source.weixin.pojo.AccessToken;
import com.source.weixin.util.WeixinUtil;
/**
* 定时获取微信access_token线程
* @author xuhj
* @date 2015-3-13
*/
public class TokenThread implements Runnable {
private static Logger log = LoggerFactory.getLogger(TokenThread.class);
//第三方用户唯一凭证
public static String appid = "";
//第三方用户唯一凭证密匙
public static String appsecret = "";
public static AccessToken accessToken = null;
public static String jsapi_ticket=null;
public void run() {
// TODO Auto-generated method stub
while(true){
try{
accessToken = WeixinUtil.getAccessToken(appid, appsecret);
//获取JSAPI_Ticket
jsapi_ticket = WeixinUtil.JSApiTIcket(accessToken.getToken());
if(null != accessToken){
log.info("获取access_token成功,有效时长{}秒 token:{}",accessToken.getExpiresIn(),accessToken.getToken());
log.info("获取jsapi_ticket成功, jsapi_ticket:{}",jsapi_ticket);
//休眠700秒
Thread.sleep((accessToken.getExpiresIn()-200)*1000);
}
else{
//如果access_token未null,60秒后在获取
Thread.sleep(60*1000);
}
}catch(InterruptedException e){
try{
Thread.sleep(60*1000);
}catch(InterruptedException e1){
log.error("{}",e1);
}
log.error("{}",e);
}
}
}
public static void main(String[] args){
System.out.println(TokenThread.accessToken.getToken());
}
}
由于把appid和appsecret写在web.xml所以也把web.xml也贴上来
This is the description of my J2EE component
This is the display name of my J2EE component
CoreServlet
com.source.weixin.servlet.CoreServlet
This is the description of my J2EE component
This is the display name of my J2EE component
InitServlet
com.source.weixin.servlet.InitServlet
appid
你的ID
appsecret
你的appsecret
0
This is the description of my J2EE component
This is the display name of my J2EE component
HttpUtil
com.source.weixin.servlet.HttpUtil
CoreServlet
/CoreServlet
HttpUtil
/HttpUtil
index.jsp
在WEB.XML文件中可以看到InitServlet就是线程调用到的servlet。由于不需要对外访问,就不需要对其进行映射,下面是IntiServlet的类代码
package com.source.weixin.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.source.weixin.thread.TokenThread;
import com.source.weixin.util.WeixinUtil;
/**
* 初始化Servlet
* @author xuhj
* @date 2015-3-13
*/
public class InitServlet extends HttpServlet {
private static final long serivalVersionUID= 1L;
private static Logger log = LoggerFactory.getLogger(WeixinUtil.class);
/**
* Constructor of the object.
*/
public InitServlet() {
super();
}
/**
* Destruction of the servlet.
*/
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}
/**
* The doGet method of the servlet.
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("");
out.println("");
out.println(" A Servlet ");
out.println(" ");
out.print(" This is ");
out.print(this.getClass());
out.println(", using the GET method");
out.println(" ");
out.println("");
out.flush();
out.close();
}
/**
* The doPost method of the servlet.
*
* This method is called when a form has its tag value method equals to post.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("");
out.println("");
out.println(" A Servlet ");
out.println(" ");
out.print(" This is ");
out.print(this.getClass());
out.println(", using the POST method");
out.println(" ");
out.println("");
out.flush();
out.close();
}
/**
* Initialization of the servlet.
*
* @throws ServletException if an error occurs
*/
public void init() throws ServletException {
// Put your code here
//获取web.xml中配置的参数
TokenThread.appid = getInitParameter("appid");
TokenThread.appsecret = getInitParameter("appsecret");
log.info("weixin api appid:{}",TokenThread.appid);
log.info("weixin api appsecret:{}",TokenThread.appsecret);
//未配置appid、appsecret时给出提示
if("".equals(TokenThread.appid )|| "".equals(TokenThread.appsecret)){
log.error("appid and appsecret configuration error,please check carefully.");
}else{
//启动定时获取access_token的线程
new Thread(new TokenThread()).start();
}
}
}
现在发一个工具类的代码 weixinutil,里面包括获取accessToken、获取JSApi_ticket、signature的加密获取的方法
package com.source.weixin.util;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.source.weixin.pojo.AccessToken;
import com.source.weixin.pojo.Menu;
import com.source.weixin.pojo.assistant.SendAssistant;
import com.source.weixin.thread.TokenThread;
/**
* 公众平台通用接口工具类
* @author xuhj
* @date 2015-3-11
*/
public class WeixinUtil {
private static Logger log = LoggerFactory.getLogger(WeixinUtil.class);
/**
* 发起https请求并获取结果
* @param requestUrl 请求地址
* @param requestMethod 请求方式(get、post)
* @param outputstr 提交的数据
* @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
*/
@SuppressWarnings("deprecation")
public static JSONObject httpRequest(String requestUrl,String requestMethod,String outputstr){
JSONObject jsonObject = null;
StringBuffer buffer = new StringBuffer();
try{
//创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = {new MyX509TrustManager()};
SSLContext sslContext = SSLContext.getInstance("SSL","SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
//从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url=new URL(requestUrl);
HttpsURLConnection httpUrlConn = (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){
OutputStream outputStream = httpUrlConn.getOutputStream();
//注意编码格式,防止中文乱码
outputStream.write(outputstr.getBytes("UTF-8"));
outputStream.close();
}
// 将返回的输入流转换成字符串
InputStream inputStream = httpUrlConn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream,"UTF-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
while((str = bufferedReader.readLine()) != null){
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
//释放资源
inputStream.close();
inputStream = null;
httpUrlConn.disconnect();
jsonObject = JSONObject.fromObject(buffer.toString());
}catch(ConnectException e){
log.error("Weixin server connection timed out.");
}catch(Exception e){
log.error("https request error:{}",e);
}
return jsonObject;
}
// 获取access_token的接口地址(GET) 限200(次/天)
public final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
/**
* 获取accessToekn
* @param appid 凭证
* @param appsecret 密匙
* @return
*/
public static AccessToken getAccessToken(String appid, String appsecret) {
AccessToken accessToken = null;
String requestUrl = access_token_url.replace("APPID", appid).replace("APPSECRET", appsecret);
JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
// 如果请求成功
if (null != jsonObject) {
try {
accessToken = new AccessToken();
accessToken.setToken(jsonObject.getString("access_token"));
accessToken.setExpiresIn(jsonObject.getInt("expires_in"));
} catch (JSONException e) {
accessToken = null;
// 获取token失败
log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
}
}
return accessToken;
}
//获取JSAPI_Ticket
public static String jsapi_ticket_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
/**
* 获取jsapi_ticket
* @param accessToken
* @return
*/
public static String JSApiTIcket(String accessToken){
int result = 0;
String jsApiTicket = null;
//拼装创建菜单Url
String url = jsapi_ticket_url.replace("ACCESS_TOKEN", TokenThread.accessToken.getToken());
//调用接口获取jsapi_ticket
JSONObject jsonObject = httpRequest(url, "GET", null);
// 如果请求成功
if (null != jsonObject) {
try {
jsApiTicket = jsonObject.getString("ticket");
} catch (JSONException e) {
if (0 != jsonObject.getInt("errcode")) {
result = jsonObject.getInt("errcode");
log.error("JSAPI_Ticket获取失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
}
}
}
return jsApiTicket;
}
/**
* sha1加密
* @param str
* @return
*/
public static String sha1Encrypt(String str){
String signature = null;
try
{
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(str.getBytes("UTF-8"));
signature = byteToHex(crypt.digest());
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
return signature;
}
private static String byteToHex(final byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash)
{
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
}
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
微信JS-SDK
AccessToken:<%=request.getAttribute("accessToken") %>
JSApi_Ticket:<%=request.getAttribute("jsapi_ticket") %>
timestamp:<%=request.getAttribute("time") %>
nonceStr:<%=request.getAttribute("randomStr") %>
signature:<%=request.getAttribute("signature") %>
onMenuShareAppMessage
hideOptionMenu
demo.js文件如下
wx.ready(function(){
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,
//所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才
//调用的接口,则可以直接调用,不需要放在ready函数中。
wx.checkJsApi({
jsApiList: ['onMenuShareAppMessage'], // 需要检测的JS接口列表,所有JS接口列表见附录2,
success: function(res) {
alert("支持onMenuShareAppMessage");
// 以键值对的形式返回,可用的api值true,不可用为false
// 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}
}
});
document.querySelector('#btn1').onclick = function () {
wx.onMenuShareAppMessage({
title: '互联网之子',
desc: '在长大的过程中,我才慢慢发现,我身边的所有事,别人跟我说的所有事,那些所谓本来如此,注定如此的事,它们其实没有非得如此,事情是可以改变的。更重要的是,有些事既然错了,那就该做出改变。',
link: 'http://movie.douban.com/subject/25785114/',
imgUrl: 'http://demo.open.weixin.qq.com/jssdk/images/p2166127561.jpg',
trigger: function (res) {
// 不要尝试在trigger中使用ajax异步请求修改本次分享的内容,因为客户端分享操作是一个同步操作,这时候使用ajax的回包会还没有返回
alert('用户点击发送给朋友');
},
success: function (res) {
alert('已分享');
},
cancel: function (res) {
alert('已取消');
},
fail: function (res) {
alert(JSON.stringify(res));
}
});
alert('已注册获取“发送给朋友”状态事件');
};
document.querySelector('#btn2').onclick = function () {
alert("hideOptionMenu");
wx.hideOptionMenu();
};
wx.error(function(res){
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,
//也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
});
});
二、微信JS SDK Demo
这个有官方Demo http://demo.open.weixin.qq.com/jssdk/
官方的说明文档 微信JS SDK说明文档