Spring Boot中微信全局token的缓存实现

摘要:
每天对网页授权令牌的调用次数没有限制,并且不需要缓存。令牌的有效时间为7200s。令牌的全局缓存实现后,每天只需调用12次。当缓存方案项目启动时,启动一个计时器,每7180秒执行一次Http请求,并从WeChat_ token获取最新的访问,并在redis_中转换旧的访问。代码中需要访问_令牌直接从缓存中读取。
 

为什么要缓存token?

这里的token指的是微信JSAPI中基础支持的ACCESS_TOKEN,并非网页授权ACCESS_TOKEN。网页授权Token每天的调用次数没有限制,不需要缓存。

接口每日限额
获取access_token2000
自定义菜单创建1000
自定义菜单查询10000
获取用户基本信息5000000
获取网页授权access_token
刷新网页授权access_token
网页授权获取用户信息

从上面的表格我们可以看到,微信基础支持的token每天调用频次为2000次。而token的有效时间为7200s,当实现了token的全局缓存后,理论每天只需要调用12次。相反,2000次即使仅供微信分享回调,在有一定用户基础的项目中完全满足不了。

缓存方案

  1. 项目启动时开启一个定时器,每7180s执行一次Http请求,从微信获取最新的access_token并将redis中旧的access_token替换掉。
  2. 代码中有需要使用access_token时,直接从缓存中读取。

Spring Boot使用定时器

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.sql.SQLException;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.bjb.dao.impl.RedisTokenHelper;

import net.sf.json.JSONObject;

/**
 * 全局定时器
 * @author qiqj
 *
 */
@Component
public class Scheduler {

    private final Logger logger = Logger.getRootLogger();

    @Resource
    private RedisTokenHelper redisTokenHelper;
    /**
     * 定时获取access_token
     * @throws SQLException 
     */
    @Scheduled(fixedDelay=7180000)
    public void getAccessToken() throws SQLException{
        logger.info("==============开始获取access_token===============");
        String access_token = null;
        String grant_type = "client_credential";
        String AppId= WxPropertiseUtil.getProperty("appid");
        String secret= WxPropertiseUtil.getProperty("secret");
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type="+grant_type+"&appid="+AppId+"&secret="+secret;  

        try {  
            URL urlGet = new URL(url);  
            HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();  
            http.setRequestMethod("GET"); // 必须是get方式请求  
            http.setRequestProperty("Content-Type","application/x-www-form-urlencoded");  
            http.setDoOutput(true);  
            http.setDoInput(true);  
            http.connect();   
            InputStream is = http.getInputStream();
            int size = is.available();  
            byte[] jsonBytes = new byte[size];  
            is.read(jsonBytes);  
            String message = new String(jsonBytes, "UTF-8");  
            JSONObject demoJson = JSONObject.fromObject(message);  
            //System.out.println("JSON字符串:"+demoJson);  
            access_token = demoJson.getString("access_token");  
            is.close();
            logger.info("==============结束获取access_token===============");
        } catch (Exception e) {  
                e.printStackTrace();  
        }
        logger.info("==============开始写入access_token===============");
        redisTokenHelper.saveObject("global_token", access_token);
        logger.info("==============写入access_token成功===============");
    }
}

读取配置文件工具类

    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Properties;

    import org.apache.log4j.Logger;
    /**
     * 读取微信配置文件  wxconfig.properties工具类
     * @author qiqj
     *
     */
    public class WxPropertiseUtil {

        private static Properties properties = new Properties();

        protected static final Logger logger = Logger.getRootLogger();

        static{
            InputStream in = WxPropertiseUtil.class.getClassLoader().getResourceAsStream("wxconfig.properties");
            try {
                properties.load(in);

            } catch (IOException e) {
                e.printStackTrace();
                logger.error(e.getMessage());
            }
        }
        public static String getProperty(String key){
            return properties.getProperty(key);
        }
        public static void UpdateProperty(String key,String value){
            properties.setProperty(key, value);
        }
    }

微信配置文件

    appid=xxxx
    secret=xxxxxx

Redis操作工具类


    import java.util.concurrent.TimeUnit;

    import javax.annotation.Resource;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.data.redis.core.ValueOperations;
    import org.springframework.stereotype.Repository;

    /**
     * 封装Redis存取Token对的工具类
     * @author qiqj
     *
     */
    @Repository
    public class RedisTokenHelper {
        @Autowired
        StringRedisTemplate stringRedisTemplate;

        @Autowired
        RedisTemplate<Object, Object> redisTemplate;

        @Resource(name="stringRedisTemplate")
        ValueOperations<String, String> ops;

        @Resource(name="redisTemplate")
        ValueOperations<Object, Object> objOps;
        /**
         * 键值对存储 字符串 :有效时间3分钟
         * @param tokenType Token的key
         * @param Token Token的值
         */
        public void save(String tokenType,String Token){
            ops.set(tokenType, Token, 180, TimeUnit.SECONDS);
        }
        /**
         * 根据key从redis获取value 
         * @param tokenType
         * @return String
         */
        public String getToken(String tokenType){
            return ops.get(tokenType);
        }
        /**
         * redis 存储一个对象
         * @param key
         * @param obj
         * @param timeout 过期时间  单位:s
         */
        public void saveObject(String key,Object obj,long timeout){
            objOps.set(key, obj,timeout,TimeUnit.SECONDS);
        }
        /**
         * redis 存储一个对象  ,不过期
         * @param key
         * @param obj
         */
        public void saveObject(String key,Object obj){
            objOps.set(key, obj);
        }
        /**
         * 从redis取出一个对象
         * @param key
         * @param obj
         */
        public Object getObject(String key){
            return objOps.get(key);
        }
        /**
         * 根据Key删除Object
         * @param key
         */
        public void removeObject(String key){
            redisTemplate.delete(key);
        }
    }

简单测试

    import org.apache.log4j.Logger;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.boot.test.SpringApplicationConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import org.springframework.test.context.web.WebAppConfiguration;
    import org.springframework.transaction.annotation.Transactional;

    import com.bjb.Application;
    import com.bjb.dao.impl.RedisTokenHelper;
    /**
     * Junit单元测试类
     * @author qiqj
     *
     */
    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringApplicationConfiguration(classes=Application.class)
    @WebAppConfiguration
    @Transactional
    public class JUnitTest {
        private final Logger logger = Logger.getRootLogger();

        @Resource
        private RedisTokenHelper redisTokenHelper;

        @Test
        public void test(){
            String access_token = (String) redisTokenHelper.getObject("global_token");
            System.out.println("access_token:"+access_token);
        }
    }

免责声明:文章转载自《Spring Boot中微信全局token的缓存实现》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇IOS--CALayer实现,界限、透明度、位置、旋转、缩放组合动画(转)Centos7网卡配置文件下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

WinForm窗体间如何传值的几种方法

(转) 窗体间传递数据,无论是父窗体操作子窗体,还是子窗体操作符窗体,有以下几种方式: 公共静态变量; 使用共有属性; 使用委托与事件; 通过构造函数把主窗体传递到从窗体中; 一、通过静态变量 特点:传值是双向的,实现简单 实现代码如下: 在一个app类中定义一个静态成员value public class app { public static st...

分布式系统唯一ID生成方案汇总

系统唯一ID是我们在设计一个系统的时候常常会遇见的问题,也常常为这个问题而纠结。生成ID的方法有很多,适应不同的场景、需求以及性能要求。所以有些比较复杂的系统会有多个ID生成的策略。下面就介绍一些常见的ID生成策略。 1. 数据库自增长序列或字段 最常见的方式。利用数据库,全数据库唯一。 优点: 1)简单,代码方便,性能可以接受。 2)数字ID天然排序,...

高仿微信新消息提示音功能

近期公司在做一个项目。有一个切换消息提示音的功能,能够切换本应用收到消息的提示音,而不影响系统提示音。我就依照微信的那个样式进行了编程,终于得到想要的效果。 转载请注明出处。谢谢:http://blog.csdn.net/harryweasley/article/details/46408037 怕有些人不知道怎么进入微信的新消息提示音功能,我这里说...

Ant Design Pro V5 从服务器请求菜单(typescript版)

【前言】 找了很多Admin模板,最后还是看中了AntDesignPro(下文简写antd pro)这个阿里巴巴开源的Admin框架,长这样(还行吧,目前挺主流的): 官网地址:https://pro.ant.design/index-cn 该套模板是使用了React开发框架作为基础,AntDesign(蚂蚁金服开源UI组件库)作为UI库,集成了Dva,...

数据绑定流程分析

1.    数据绑定流程原理★ ①   Spring MVC 主框架将 ServletRequest  对象及目标方法的入参实例传递给 WebDataBinderFactory 实例,以创建 DataBinder 实例对象 ②   DataBinder 调用装配在 Spring MVC 上下文中的 ConversionService 组件进行数据类型转换、...

关于直接下载第三方IPA应用分发平台之蒲公英的研究

目前基于第三方应用分发的平台比较常用的就属蒲公英、fir等,在我们提交到平台后,我们可以通过扫描应用二维码来下载,比如蒲公英平台如下: 那么以上是非常普通的一个操作过程,问题来了:如何直接在电脑端下载IPA安装包呢,即不通过手机来下载安装包直接安装,我们想把IPA直接提取出来研究或分享。 常规模式: 1,通过浏览器调试模式,切换到移动设备,即可通过点击安...