您的位置:首页 > 移动开发 > 微信开发

微信JS-SDK入门(JAVA版)

2015-03-17 17:19 316 查看
这个给大家分享一下微信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. <br>
*/
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}

/**
* The doGet method of the servlet. <br>
*
* 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. <br>
*
* 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("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
out.println("<HTML>");
out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");
out.println("  <BODY>");
out.print("    This is ");
out.print(this.getClass());
out.println(", using the POST method");
out.println("  </BODY>");
out.println("</HTML>");
out.flush();
out.close();
}

/**
* Initialization of the servlet. <br>
*
* @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也贴上来

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name></display-name>
<servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<servlet-name>CoreServlet</servlet-name>
<servlet-class>com.source.weixin.servlet.CoreServlet</servlet-class>
</servlet>
<servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<servlet-name>InitServlet</servlet-name>
<servlet-class>com.source.weixin.servlet.InitServlet</servlet-class>
<!-- 配置获取access_token所需参数appid和appsecret -->
<init-param>
<param-name>appid</param-name>
<param-value>你的ID</param-value>
</init-param>
<init-param>
<param-name>appsecret</param-name>
<param-value>你的appsecret</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<servlet-name>HttpUtil</servlet-name>
<servlet-class>com.source.weixin.servlet.HttpUtil</servlet-class>
</servlet>

<!-- url-pattern 中配置的/coreServlet用于指定该Servlet的访问路径 -->
<servlet-mapping>
<servlet-name>CoreServlet</servlet-name>
<url-pattern>/CoreServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>HttpUtil</servlet-name>
<url-pattern>/HttpUtil</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>


在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. <br>
*/
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}

/**
* The doGet method of the servlet. <br>
*
* 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("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
out.println("<HTML>");
out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");
out.println("  <BODY>");
out.print("    This is ");
out.print(this.getClass());
out.println(", using the GET method");
out.println("  </BODY>");
out.println("</HTML>");
out.flush();
out.close();
}

/**
* The doPost method of the servlet. <br>
*
* 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("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
out.println("<HTML>");
out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");
out.println("  <BODY>");
out.print("    This is ");
out.print(this.getClass());
out.println(", using the POST method");
out.println("  </BODY>");
out.println("</HTML>");
out.flush();
out.close();
}

/**
* Initialization of the servlet. <br>
*
* @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;
}

}


其他的微信默认实体类就不发了。 建立一个jsp页面,名字为demo.jsp

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">

<title>微信JS-SDK</title>

<meta http-equiv="pragma" content="no-cache">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="renderer" content="webkit">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
<script type="text/javascript" src="js/demo.js"></script>
<script type="text/javascript">
wx.config({
debug:true,//开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId:'wx2dc5ea7a6e38342f',//必填,公众号唯一标识
timestamp:'<%=request.getAttribute("time") %>', //必填,生成签名的时间戳
nonceStr:'<%=request.getAttribute("randomStr") %>', //必填,生产签名的随机串
signature:'<%=request.getAttribute("signature") %>', //必填,签名,
jsApiList:['onMenuShareAppMessage','hideOptionMenu'] //必填,需要使用的JS接口列表
});

</script>
</head>

<body>
AccessToken:<%=request.getAttribute("accessToken") %><br/>
JSApi_Ticket:<%=request.getAttribute("jsapi_ticket") %><br/>
timestamp:<%=request.getAttribute("time") %><br/>
nonceStr:<%=request.getAttribute("randomStr") %><br/>
signature:<%=request.getAttribute("signature") %><br/>
<a href="javascript:void(0);" id="btn1" >onMenuShareAppMessage</a><br/><br/>
<a href="javascript:void(0);" id="btn2">hideOptionMenu</a>
</body>
</html>


demo.js文件如下

<pre name="code" class="javascript">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可以在这里更新签名。
});
});



运行项目直接访问sevlet就可以看到结果了。

二、微信JS SDK Demo

这个有官方Demo http://demo.open.weixin.qq.com/jssdk/

官方的说明文档 微信JS
SDK说明文档
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: