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);
            }
        }
  • 相关阅读:
    小波变换的引入,通俗易懂
    Leetcode 437. Path Sum III
    Leetcode 113. Path Sum II
    Leetcode 112 Path Sum
    Leetcode 520 Detect Capital
    Leetcode 443 String Compression
    Leetcode 38 Count and Say
    python中的生成器(generator)总结
    python的random模块及加权随机算法的python实现
    leetcode 24. Swap Nodes in Pairs(链表)
  • 原文地址:https://www.cnblogs.com/stupidMartian/p/9262947.html
Copyright © 2011-2022 走看看