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); } }

猜你喜欢

转载自www.cnblogs.com/stupidMartian/p/9262947.html