为什么要缓存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);
}
}

Spring Boot中微信全局token的缓存实现的更多相关文章

  1. Spring Boot 中集成 Redis 作为数据缓存

    只添加注解:@Cacheable,不配置key时,redis 中默认存的 key 是:users::SimpleKey [](1.redis-cli 中,通过命令:keys * 查看:2.key:缓存 ...

  2. Spring Boot2 系列教程(十三)Spring Boot 中的全局异常处理

    在 Spring Boot 项目中 ,异常统一处理,可以使用 Spring 中 @ControllerAdvice 来统一处理,也可以自己来定义异常处理方案.Spring Boot 中,对异常的处理有 ...

  3. 在Spring Boot中添加全局异常捕捉提示

    在一个项目中的异常我们我们都会统一进行处理的,那么如何进行统一进行处理呢? 全局异常捕捉: 新建一个类GlobalDefaultExceptionHandler, 在class注解上@Controll ...

  4. Spring Boot中使用缓存

    Spring Boot中使用缓存 随着时间的积累,应用的使用用户不断增加,数据规模也越来越大,往往数据库查询操作会成为影响用户使用体验的瓶颈,此时使用缓存往往是解决这一问题非常好的手段之一. 原始的使 ...

  5. Spring Boot中的缓存支持(一)注解配置与EhCache使用

    Spring Boot中的缓存支持(一)注解配置与EhCache使用 随着时间的积累,应用的使用用户不断增加,数据规模也越来越大,往往数据库查询操作会成为影响用户使用体验的瓶颈,此时使用缓存往往是解决 ...

  6. spring boot中的声明式事务管理及编程式事务管理

    这几天在做一个功能,具体的情况是这样的: 项目中原有的几个功能模块中有数据上报的功能,现在需要在这几个功能模块的上报之后生成一条消息记录,然后入库,在写个接口供前台来拉取消息记录. 看到这个需求,首先 ...

  7. Spring Boot中的微信支付(小程序)

    前言 微信支付是企业级项目中经常使用到的功能,作为后端开发人员,完整地掌握该技术是十分有必要的. logo 一.申请流程和步骤 图1-1 注册微信支付账号 获取微信小程序APPID 获取微信商家的商户 ...

  8. 在Spring Boot中使用数据缓存

    春节就要到了,在回家之前要赶快把今年欠下的技术债还清.so,今天继续.Spring Boot前面已经预热了n篇博客了,今天我们来继续看如何在Spring Boot中解决数据缓存问题.本篇博客是以初识在 ...

  9. Spring Boot中使用EhCache实现缓存支持

     SpringBoot提供数据缓存功能的支持,提供了一系列的自动化配置,使我们可以非常方便的使用缓存.,相信非常多人已经用过cache了.因为数据库的IO瓶颈.一般情况下我们都会引入非常多的缓存策略, ...

随机推荐

  1. java内存查看与分析

    业界有很多强大的java profile的工具,比如Jporfiler,yourkit,这些收费的东西我就不想说了,想说的是,其实java自己就提供了很多内存监控的小工具,下面列举的工具只是一小部分, ...

  2. QPushButton注册事件过滤器后按钮消失

    版权声明:本文为博主原创文章,转载需要注明出处. RT,代码如下: ui.btn_set->installEventFilter(this); bool MousrHoverTest::even ...

  3. node.js入门之二

    NPM 1.NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题,常见的使用场景有以下几种: 允许用户从NPM服务器下载别人编写的第三方包到本地使用. 允许用户从NPM ...

  4. 田字格布局html div

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  5. Android(java)学习笔记196:ContentProvider使用之内容观察者01

    1. 内容观察者 不属于四大组件,只是内容提供者ContentProvider对应的小功能. 如果发现数据库内容变化了,就会立刻观察到. 下面是逻辑图:       当A应用中银行内部的数据发生变化的 ...

  6. caffe和图像一些基础知识

    1.卷积层的参数放置在convoluytion_param{}中,pad默认是0,stride默认是1,如果在convoluytion_param中没有写pad = 什么,或者stride = 什么, ...

  7. 第2节 mapreduce深入学习:4, 5

    第2节 mapreduce深入学习:4.mapreduce的序列化以及自定义排序 序列化(Serialization)是指把结构化对象转化为字节流. 反序列化(Deserialization)是序列化 ...

  8. 关于C/C++的一些思考(2)

    C++引入类机制的目的: 从语法上将数据和操作捆绑在一起: 从语法上消除变量和函数的名字冲突: 从语法上允许服务端设计者控制数据和函数的访问权限: 从工程上支持数据封装.信息隐藏.将责任推向服务端.减 ...

  9. Vue实例方法之事件的实现

    开始 这段时间一直在看vue的源码,源码非常多和杂,所以自己结合资料和理解理出了一个主线,然后根据主线去剥离其他的一些知识点,然后将各个知识点逐一学习.这里主要是分析的Vue事件处理的实现. 正文 一 ...

  10. Python之机器学习-波斯顿房价预测

    目录 波士顿房价预测 导入模块 获取数据 打印数据 特征选择 散点图矩阵 关联矩阵 训练模型 可视化 波士顿房价预测 导入模块 import pandas as pd import numpy as ...