为了使第三方开发人员能够为用户提供很多其它更有价值的个性化服务,微信公众平台开放了很多接口,包含自己定义菜单接口、客服接口、获取用户信息接口、用户分组接口、群发接口等,开发人员在调用这些接口时。都须要传入一个同样的參数access_token。它是公众账号的全局唯一票据。它是接口訪问凭证。

access_token的有效期是7200秒(两小时),在有效期内。能够一直使用。仅仅有当access_token过期时,才须要再次调用接口获取access_token。在理想情况下,一个7x24小时执行的系统,每天仅仅须要获取12次access_token,即每2小时获取一次。

假设在有效期内。再次获取access_token,那么上一次获取的access_token将失效。

眼下,获取access_token接口的调用频率限制为2000次/天,假设每次发送客服消息、获取用户信息、群发消息之前都要先调用获取access_token接口得到接口訪问凭证,这显然是不合理的,一方面会更耗时(多了一次接口调用操作),另一方面2000次/天的调用限制恐怕也不够用。因此,在实际应用中,我们须要将获取到的access_token存储起来,然后定期调用access_token接口更新它,以保证随时取出的access_token都是有效的。

以下将为大家介绍怎样定时获取并存储access_token。请注意:这不是一篇解说怎样调用接口获取access_token的文章。关于access_token的获取,请參考文章《微信公众帐号开发教程第14篇-自己定义菜单的创建及菜单事件响应》

在动手前先来简单分析一下,我们要解决的无非是例如以下两个问题:

1、怎样定时获取access_token?

在Java中,假设要定时执行某项任务。须要用到java.util.Timer类。对于喜欢使用框架的朋友。能够採用开源的任务调度框架quartz,Spring框架也支持quartz。

除此这外,另一种方法就是启动一个线程,在线程的run()方法中写一个死循环,然后使用Thread.sleep()来保证线程定时执行某项任务。

2、将access_token保存在哪?

对于access_token的存储,能够考虑存储在文件、数据库或内存中。详细採用哪种存储方式,须要依据项目实际情况而定。假设仅仅有一台server。直接将access_token存储在内存中是最简便有效的方式。

在本文中,笔者将演示的定期获取并存储access_token的流程为:Webserver启动时就载入一个Servlet。在Servlet的init()方法中启动一个线程,在线程的run()方法中通过死循环+Thread.sleep()的方式定期获取access_token,然后将获取到的access_token保存在public static修饰的变量中。

在project中创建一个InitServlet类,该类的代码例如以下:

package org.liufeng.weixin.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import org.liufeng.weixin.thread.TokenThread;
import org.liufeng.weixin.util.WeixinUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; /**
* 初始化servlet
*
* @author liuyq
* @date 2013-05-02
*/
public class InitServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static Logger log = LoggerFactory.getLogger(WeixinUtil.class); public void init() throws ServletException {
// 获取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();
}
}
}

从上面的代码能够看出,InitServlet类仅仅重写了init()方法,并没有重写doGet()和doPost()两个方法,由于我们并不打算让InitServlet来处理訪问请求。init()方法的实现也比較简单,先获取在web.xml中配置的參数appid和appsecret,再启动线程TokenThread定时获取access_token。

InitServlet在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"> <servlet>
<servlet-name>initServlet</servlet-name>
<servlet-class>
org.liufeng.weixin.servlet.InitServlet
</servlet-class>
<!-- 配置获取access_token所需參数appid和appsecret -->
<init-param>
<param-name>appid</param-name>
<param-value>wx617a123bb8bc99cd</param-value>
</init-param>
<init-param>
<param-name>appsecret</param-name>
<param-value>4d82cbbbb08714c12345b62d7hn3dcb8</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet> <welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

InitServlet在web.xml中的配置与普通Servlet的配置有几点差别:1)通过配置<init-param>向Servlet中传入參数;2)通过配置<load-on-startup>使得Webserver启动时就载入该Servlet;3)没有配置<servlet-mapping>,由于InitServlet并不正确外提供訪问。

TokenThread的源码例如以下:

package org.liufeng.weixin.thread;

import org.liufeng.weixin.pojo.AccessToken;
import org.liufeng.weixin.util.WeixinUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; /**
* 定时获取微信access_token的线程
*
* @author liuyq
* @date 2013-05-02
*/
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 void run() {
while (true) {
try {
accessToken = WeixinUtil.getAccessToken(appid, appsecret);
if (null != accessToken) {
log.info("获取access_token成功,有效时长{}秒 token:{}", accessToken.getExpiresIn(), accessToken.getToken());
// 休眠7000秒
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);
}
}
}
}

代码中的第23行通过while(true){}构造了一个死循环(永久执行);第25行调用公众平台接口获取access_token。第29行让线程休眠7000秒再执行,即每隔7000秒获取一次access_token,保证access_token永不失效。

在项目中的其它类,能够通过调用 TokenThread.accessToken.getToken() 来得到接口訪问凭证access_token。

在本地部署执行该程序,Tomcat启动完毕后就会在控制台显演示样例如以下日志:

[INFO ] weixin api appid:wx617a123bb8bc99cd
[INFO ] weixin api appsecret:4d82cbbbb08714c12345b62d7hn3dcb8
[INFO ] 获取access_token成功。有效时长7200秒 token:sFopJ9lMmLl4u-ad61ojKpS0TolhN2s3SnHoI2Mh5GgdiYb35i-7DG2T2CDyQKMe

为了能够直观看到定期获取access_token的效果,能够试着将TokenThread里的线程休眠时间改动为30秒或60秒。最后,附上本文所涉及的项目源码。下载地址:http://download.csdn.net/detail/lyq8479/7300501

PS:2014年4月25日微信团队公布了改动access_token长度的通知,非常多开发人员问这次改动会对我们的程序产生什么影响,这里顺便回答一下:假设开发人员将获取到的access_token存入数据库。就必须保证相应的字段长度足够大,至少能存储512个字符。假设开发人员是将access_token存储在内存中,那什么都不须要改动。

假设认为文章对你有所帮助,请通过留言或关注微信公众帐号xiaoqrobot来支持柳峰!

转帖请注明本文出自柳峰的博客(http://blog.csdn.net/lyq8479),请尊重他人的辛勤劳动成果,谢谢!

[051] 微信公众平台开发教程第22篇-怎样保证access_token长期有效的更多相关文章

  1. Senparc.Weixin.MP SDK 微信公众平台开发教程(二十一):在小程序中使用 WebSocket (.NET Core)

    本文将介绍如何在 .NET Core 环境下,借助 SignalR 在小程序内使用 WebSocket.关于 WebSocket 和 SignalR 的基础理论知识不在这里展开,已经有足够的参考资料, ...

  2. Senparc.Weixin.MP SDK 微信公众平台开发教程(十八):Web代理功能

    在Senparc.Weixin.dll v4.5.7版本开始,我们提供了Web代理功能,以方便在受限制的局域网内的应用可以顺利调用接口. 有关的修改都在Senparc.Weixin/Utilities ...

  3. Senparc.Weixin.MP SDK 微信公众平台开发教程(十七):个性化菜单接口说明

    前不久微信上线了个性化菜单接口,Senparc.Weixin SDK也已经同步更新. 本次更新升级Senparc.Weixin.MP版本到v13.5.2,依赖Senparc.Weixin版本4.5.4 ...

  4. Senparc.Weixin.MP SDK 微信公众平台开发教程(三):微信公众平台开发验证

    要对接微信公众平台的"开发模式",即对接到自己的网站程序,必须在注册成功之后(见Senparc.Weixin.MP SDK 微信公众平台开发教程(一):微信公众平台注册),等待官方 ...

  5. Senparc.Weixin.MP SDK 微信公众平台开发教程(四):Hello World

    =============  以下写于2013-07-20 ============= 这一篇文章其实可以写在很前面,不过我还是希望开发者们尽多地了解清楚原理之后再下手. 通过上一篇Senparc.W ...

  6. Senparc.Weixin.MP SDK 微信公众平台开发教程(五):使用Senparc.Weixin.MP SDK

    Senparc.Weixin.MP SDK已经涵盖了微信6.x的所有公共API. 整个项目的源代码以及已经编译好的程序集可以在这个项目中获取到:https://github.com/JeffreySu ...

  7. Senparc.Weixin.MP SDK 微信公众平台开发教程(六):了解MessageHandler

    上一篇<Senparc.Weixin.MP SDK 微信公众平台开发教程(五):使用Senparc.Weixin.MP SDK>我们讲述了如何使用Senparc.Weixin.MP SDK ...

  8. Senparc.Weixin.MP SDK 微信公众平台开发教程(七):解决用户上下文(Session)问题

    从这篇文章中我们已经了解了微信公众平台消息传递的方式,这种方式有一个先天的缺陷:不同用户的请求都来自同一个微信服务器,这使得常规的Session无法使用(始终面对同一个请求对象,况且还有对方服务器Co ...

  9. Senparc.Weixin.MP SDK 微信公众平台开发教程(八):通用接口说明

    一.基础说明 这里说的“通用接口(CommonAPIs)”是使用微信公众账号一系列高级功能的必备验证功能(应用于开发模式). 我们通过微信后台唯一的凭证,向通用接口发出请求,得到访问令牌(Access ...

随机推荐

  1. DOM笔记(九):引用类型、基本包装类型和单体内置对象

    一.Array 1 .创建数组的方式 //Array构造函数(可以去掉new) var colors0 = new Array(); var colors1 = new Array(20); var ...

  2. Chapter15:派生类

    在C++语言中,基类将类型相关的函数与派生类不做改变直接继承的函数区别对待,对于某些函数,基类希望它的派生类各自定义适合自身的版本,此时基类就将这些函数声明为虚函数. 派生类必须将其继承而来的成员函数 ...

  3. C++标准转换运算符 --四种

    具体归纳如下: reinterpret_cast 函数将一个类型的指针转换为另一个类型的指针. 这种转换不用修改指针变量值存放格式(不改变指针变量值),只需在编译时重新解释指针的类型就可做到.rein ...

  4. c#中格式化导出Excel数据

    在项目开发过程中经常会遇到数据导出Excel.如果只是导出数据就好办了.但往往用户会有各种格式要求.加粗.边框.合并单元格.汇总等功能. 以下的方法是基于Excel模版方式写入数据导出的功能.可以最大 ...

  5. Fedora20 编译安装qemu-system

    安装简介: 1.1. 本次编译安装所有的操作都在Fedora 20 x86-64上,内核版本为: 3.14.4-200.fc20.x86_64.如果在其他系统编译安装,请看其他文章. 2.安装准备: ...

  6. css 样式大全

    字体属性:(font) 大小 {font-size: x-large;}(特大) xx-small;(极小) 一般中文用不到,只要用数值就可以,单位:PX.PD 样式 {font-style: obl ...

  7. datagrid url json

    <div class="easyui-accordion" style="width:500px;height:300px;"> <div t ...

  8. Java对信号的处理

    本文主要包括Java如何处理信号,直接上代码. 1. 实现SignalHandler package com.chzhao.SignalTest; import sun.misc.*; @Suppre ...

  9. Win7系统下利用U盘安装Ubuntu14.04麒麟版

    转自http://www.360doc.cn/article/14743053_335473181.html 重要提示:在采用u盘安装ubuntu分区时,所有磁盘一定要全部设置成逻辑分区,包括根目录/ ...

  10. Android SDK Manager更新不了的解决办法

    android SDK Manager更新不了,出现错误提示:"Failed to fetch URL..."! 可以用以下办法解决: 使用SDK Manager更新时出现问题 F ...