技术交流请加QQ群:Jeewx微信开发④【289709451】

为了使第三方开发者能够为用户提供更多更有价值的个性化服务,微信公众平台开放了许多接口,包括自定义菜单接口、客服接口、获取用户信息接口、用户分组接口、群发接口等,开发者在调用这些接口时,都需要传入一个相同的参数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的存储,可以考虑存储在文件、数据库或内存中。具体采用哪种存储方式,需要根据项目实际情况而定。如果只有一台服务器,直接将access_token存储在内存中是最简便有效的方式。

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

在工程中创建一个InitServlet类,该类的代码如下:

  1. package org.liufeng.weixin.servlet;
  2. import javax.servlet.ServletException;
  3. import javax.servlet.http.HttpServlet;
  4. import org.liufeng.weixin.thread.TokenThread;
  5. import org.liufeng.weixin.util.WeixinUtil;
  6. import org.slf4j.Logger;
  7. import org.slf4j.LoggerFactory;
  8. /**
  9. * 初始化servlet
  10. *
  11. * @author liuyq
  12. * @date 2013-05-02
  13. */
  14. public class InitServlet extends HttpServlet {
  15. private static final long serialVersionUID = 1L;
  16. private static Logger log = LoggerFactory.getLogger(WeixinUtil.class);
  17. public void init() throws ServletException {
  18. // 获取web.xml中配置的参数
  19. TokenThread.appid = getInitParameter("appid");
  20. TokenThread.appsecret = getInitParameter("appsecret");
  21. log.info("weixin api appid:{}", TokenThread.appid);
  22. log.info("weixin api appsecret:{}", TokenThread.appsecret);
  23. // 未配置appid、appsecret时给出提示
  24. if ("".equals(TokenThread.appid) || "".equals(TokenThread.appsecret)) {
  25. log.error("appid and appsecret configuration error, please check carefully.");
  26. } else {
  27. // 启动定时获取access_token的线程
  28. new Thread(new TokenThread()).start();
  29. }
  30. }
  31. }

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

InitServlet在web.xml中的配置如下:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
  5. http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  6. <servlet>
  7. <servlet-name>initServlet</servlet-name>
  8. <servlet-class>
  9. org.liufeng.weixin.servlet.InitServlet
  10. </servlet-class>
  11. <!-- 配置获取access_token所需参数appid和appsecret -->
  12. <init-param>
  13. <param-name>appid</param-name>
  14. <param-value>wx617a123bb8bc99cd</param-value>
  15. </init-param>
  16. <init-param>
  17. <param-name>appsecret</param-name>
  18. <param-value>4d82cbbbb08714c12345b62d7hn3dcb8</param-value>
  19. </init-param>
  20. <load-on-startup>0</load-on-startup>
  21. </servlet>
  22. <welcome-file-list>
  23. <welcome-file>index.jsp</welcome-file>
  24. </welcome-file-list>
  25. </web-app>

InitServlet在web.xml中的配置与普通Servlet的配置有几点区别:1)通过配置<init-param>向Servlet中传入参数;2)通过配置<load-on-startup>使得Web服务器启动时就加载该Servlet;3)没有配置<servlet-mapping>,因为InitServlet并不对外提供访问。

TokenThread的源代码如下:

  1. package org.liufeng.weixin.thread;
  2. import org.liufeng.weixin.pojo.AccessToken;
  3. import org.liufeng.weixin.util.WeixinUtil;
  4. import org.slf4j.Logger;
  5. import org.slf4j.LoggerFactory;
  6. /**
  7. * 定时获取微信access_token的线程
  8. *
  9. * @author liuyq
  10. * @date 2013-05-02
  11. */
  12. public class TokenThread implements Runnable {
  13. private static Logger log = LoggerFactory.getLogger(TokenThread.class);
  14. // 第三方用户唯一凭证
  15. public static String appid = "";
  16. // 第三方用户唯一凭证密钥
  17. public static String appsecret = "";
  18. public static AccessToken accessToken = null;
  19. public void run() {
  20. while (true) {
  21. try {
  22. accessToken = WeixinUtil.getAccessToken(appid, appsecret);
  23. if (null != accessToken) {
  24. log.info("获取access_token成功,有效时长{}秒 token:{}", accessToken.getExpiresIn(), accessToken.getToken());
  25. // 休眠7000秒
  26. Thread.sleep((accessToken.getExpiresIn() - 200) * 1000);
  27. } else {
  28. // 如果access_token为null,60秒后再获取
  29. Thread.sleep(60 * 1000);
  30. }
  31. } catch (InterruptedException e) {
  32. try {
  33. Thread.sleep(60 * 1000);
  34. } catch (InterruptedException e1) {
  35. log.error("{}", e1);
  36. }
  37. log.error("{}", e);
  38. }
  39. }
  40. }
  41. }

代码中的第23行通过while(true){}构造了一个死循环(永久执行);第25行调用公众平台接口获取access_token;第29行让线程休眠7000秒再运行,即每隔7000秒获取一次access_token,保证access_token永不失效。 在项目中的其他类,可以通过调用  TokenThread.accessToken.getToken()  来得到接口访问凭证access_token。在本地部署运行该程序,Tomcat启动完成后就会在控制台显示如下日志:

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

为了能够直观看到定期获取access_token的效果,可以试着将TokenThread里的线程休眠时间修改为30秒或60秒。

PS:2014年4月25日微信团队发布了修改access_token长度的通知,如果开发者将获取到的access_token存入数据库,就必须保证对应的字段长度足够大,至少能存储512个字符;如果开发者是将access_token存储在内存中,那什么都不需要修改。

微信公众平台开发教程第22篇-如何保证access_token长期有效相关推荐

  1. 微信公众平台开发教程第2篇-----微信开发者接入

    原文地址为: 微信公众平台开发教程第2篇-----微信开发者接入 最近几天在群里看到没有接触过开发的朋友也有在玩微信的公众平台,微信用户到目前已经达到3个亿了吧!!  我不知道伙伴们是因为什么而接触微 ...

  2. 微信公众平台开发教程第20篇-新手解惑40则

    笔者在CSDN博客频道推出微信公众平台开发教程之后,接触了许多公众平台开发爱好者,也帮助他们解决了许多实际的问题,当然这其中有很多问题都是重复的,因此,笔者将这些问题及解答整理出来,以帮助更多初学者少 ...

  3. [044] 微信公众平台开发教程第20篇-新手解惑40则

    笔者在CSDN博客频道推出微信公众平台开发教程之后,接触了许多公众平台开发爱好者,也帮助他们解决了许多实际的问题,当然这其中有很多问题都是重复的,因此,笔者将这些问题及解答整理出来,以帮助更多初学者少 ...

  4. 微信公众平台开发教程第21篇-“可信网址”白名单

    防欺诈警告 不知道读者是否留意过这种情况:通过微信内置浏览器打开带有表单的页面,点击其中任何一个表单项都会在窗口顶部显示红色背景的防欺诈警告信息"防欺诈盗号,请勿支付或输入qq密码" ...

  5. [045] 微信公众平台开发教程第21篇-“可信网址”白名单

    防欺诈警告 不知道读者是否留意过这种情况:通过微信内置浏览器打开带有表单的页面,点击其中任何一个表单项都会在窗口顶部显示红色背景的防欺诈警告信息"防欺诈盗号,请勿支付或输入qq密码" ...

  6. 微信公众平台开发教程第19篇-应用实例之人脸检测

    人脸检测属于人脸识别的范畴,它是一个复杂的具有挑战性的模式匹配问题,国内外许多组织.科研机构都在专门研究该问题.国内的Face++团队专注于研发人脸检测.识别.分析和重建技术,并且向广大开发者开放了人 ...

  7. java微信公众号开发教程_微信公众平台开发教程(java版本含代码) 中文PDF版 3.13MB...

    本文档将对即将推出的微信公众帐号开发系列连载教程做简单的说明. 教程主要是面向有一定 Java 编程基础的朋友, 目录: 微信公众帐号开发教程第 1 篇-引言  2 微信公众帐号开发教程第 2 篇-微 ...

  8. Senparc.Weixin.MP SDK 微信公众平台开发教程(十一):高级接口说明

    这里所说的高级接口是指面向通过认证的服务号开通的高级功能. 高级功能大致可以分类为: 用户接口 分组接口 客服接口(有别于之前介绍的多客服) 群发接口 多媒体接口 二维码接口 模板消息接口(不是所有账 ...

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

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

最新文章

  1. 如何快速实现物联网行业中的实名认证
  2. mysql编辑表php源码_MySQL修改表的实际应用代码示例
  3. Can‘t connect to MySQL server on ‘localhost‘ (10061) 解决方法
  4. 【强化学习】AC注释版本
  5. 调用布尔变量java_关于java的参数的调用,还有布尔的理解,这有一段代码,我有些不太理解,希望能够帮我分析下,谢谢...
  6. Zabbix监控(十六):分布式监控-Zabbix Proxy
  7. 【视频特辑】提效神器,如何用Quick BI高效配置员工的用数权限
  8. valgrind 内存泄漏_应用 AddressSanitizer 发现程序内存错误
  9. html文本框最小数字,HTML5中的数字类型的输入框:数字选择器
  10. Web Hacking 101 中文版 八、跨站请求伪造
  11. ReentrantLock 公平锁和非公平锁加锁和解锁源码分析(简述)
  12. 生意场逃不开三个关键词:留存、转化、数据
  13. Zigbee 学习计划——第3天——熟悉CC2530的基本例程(续)
  14. C+++之insert()
  15. 好好编程-物流项目20【客户管理-删除客户】
  16. WPS宏不可用解决方法
  17. 解决npm只能使用管理员权限安装
  18. hp服务器怎么装win7系统,惠普280 Pro G4台式机intel 8代cpu安装win7步骤
  19. EverEdit使用正则替换
  20. PNAS:大脑是如何计算主观价值的?

热门文章

  1. 计算机网络之数据链路层:8、介质访问控制之信道划分介质访问控制
  2. Python-闭包详解
  3. 计算两个矩阵相乘(Java)
  4. 读取pdf文件信息(pdfinfo)
  5. 大数据学习——免密登录配置
  6. leetcode 103. 二叉树的锯齿形层次遍历
  7. Python基础学习总结(六)
  8. s2sh删掉原本的s2sh project capabilities后重新添加它们
  9. 涨知识了!阿里、百度、腾讯的名字竟然是这样来的
  10. Windows环境下的NodeJS+NPM+Bower安装配置步骤