• 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);
            }
        }
  • 相关阅读:
    sina sae搭建wordpress数据库配置
    Daper返回DataTable
    第4章 jQuery中的事件和动画
    第3章 ,jQuery中的DOM操作
    第2章 jQuery选择器
    第1章 认识jQuery
    MyBatis基本查询、条件查询、查询排序
    《Head First Servlets & JSP》-13-过滤器和包装器
    《Head First Servlets & JSP》-12-Web应用安全
    《Head First Servlets & JSP》-11-Web应用部署
  • 原文地址:https://www.cnblogs.com/stupidMartian/p/9262947.html
Copyright © 2020-2023  润新知