zoukankan      html  css  js  c++  java
  • Spring Boot中微信全局token的缓存实现

     

    为什么要缓存token?

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

    接口每日限额
    获取access_token 2000
    自定义菜单创建 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);
            }
        }
  • 相关阅读:
    Sqlserver 实际开发中表变量的用法
    Python Day 20 面向对象 (面向对象的组合用法,面向对象的三大特性
    Python Day 19 面向对象(初识面向对象)
    Python Day 18 常用模块(模块和包)
    Python Day 17 常用模块(常用模块一 时间模块,random模块,os模块,sys模块,序列化模块)
    Python Day 15 函数(递归函数、二分查找算法)
    Python Day 14 函数(内置函数,匿名函数(lambda表达式))
    Python Day 13 函数(迭代器,生成器,列表推导式,生成器表达式)
    Python Day 11 + Python Day 12 函数(函数名的应用,闭包,装饰器)
    Python Day 10 函数(名称空间,作用域,作用域链,加载顺序等; 函数的嵌套 global,nonlocal)
  • 原文地址:https://www.cnblogs.com/stupidMartian/p/9262947.html
Copyright © 2011-2022 走看看