微信JS-SDK入门(JAVA版)
2015-03-17 17:19
316 查看
这个给大家分享一下微信JS-SDK的基本使用,经过一天时间的研究终于可以顺利把JS-SDK连接成功了。下面就跟大家一起分享一下我的方法,当然我也是参照其他的大神来写的。
首先,建立一个servlet命名未HttpUtil
这里参考了柳峰老师的方法,写一个线程ThokenThread。 默认初始化调用来存储AccessToken和JSApi_Ticket。线程有效时间为7000秒。由于官方的有效时间为7200秒,而且每天的请求次数有一定的限制,所以设置成7000秒比较合适点。
下面是TokenThread类的代码:
由于把appid和appsecret写在web.xml所以也把web.xml也贴上来
在WEB.XML文件中可以看到InitServlet就是线程调用到的servlet。由于不需要对外访问,就不需要对其进行映射,下面是IntiServlet的类代码
现在发一个工具类的代码 weixinutil,里面包括获取accessToken、获取JSApi_ticket、signature的加密获取的方法
其他的微信默认实体类就不发了。 建立一个jsp页面,名字为demo.jsp
demo.js文件如下
运行项目直接访问sevlet就可以看到结果了。
二、微信JS SDK Demo
这个有官方Demo http://demo.open.weixin.qq.com/jssdk/
官方的说明文档 微信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说明文档
相关文章推荐
- Java 微信JS SDK 入门(网页内获取地理信息)
- 微信js sdk分享开发摘记java版
- 微信&java 开发7 js sdk 获取签名 signature
- Java企业微信开发_10_未验证域名归属,JS-SDK功能受限
- java如何快速接入微信JS-SDK
- JAVA调用微信投放卡券——HTML5线上发券(JS-SDK接口)
- 微信JS-SDK开发 入门指南
- java接入微信js-sdk
- 微信 java 实现js-sdk 图片上传下载完整流程
- java微信开发引入jssdk一直报invalid url domain错的其他原因
- java微信开发(wechat4j)——支持微信JS-SDK的jsapi_ticket中控服务器
- 夺命雷公狗---微信开发54----微信js-sdk接口开发(1)之快速入门
- 微信开发:js sdk 分享(java)
- 微信开发之JSSDK接口开发(Java)
- Java微信开发(三)之JS-SDK配置
- 微信开发(2):微信js sdk分享朋友圈,朋友,获取config接口注入权限验证(java)
- 微信js-sdk图片上传下载——java完整流程
- java微信js SDK页面签名
- Java实现微信JS-SDK【一】配置篇