access_token每隔两个小时获取一次解决方案

本文介绍微信公众号access_token的三种管理策略:SpringTask定时任务、Redis存储与线程循环获取。探讨了access_token的有效期、存储需求及调用限制,并详细解释了各种策略的实现方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

access_token是公众号的全局唯一接口调用凭据,
公众号调用各接口时都需使用access_token,access_token 有效期2小时,过期后需要重新获取 , 两次获取access_token中间有5分钟的顺延时间。开发者需要进行妥善保存。
access_token的存储至少要保留512个字符空间。
access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。
access_token每日调用上限次数是2000次/日。

问题:

每隔两个小时获取一次sccess_token;

解决方案:
  1. SpringTask定时任务

  2. 存在redis中,设置redis过期时间,过期后重新获取(完整配置redis)

  3. 线程

  4. 存在mysql中,但是考虑访问次数与效率,这里放弃

  5. IO流存在文件中,频繁读写,放弃

这是获取access_token的公共方法,在每个方法都会使用

public class AccessTokenCommon {
    public final static String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
    public final static String APPID = "APPID";
    public final static String APPSECRET = "APPSECRET值";

    public  static String ACCESS_TOKEN=null;
}

第一种方式:SpringTask定时任务

每两个小时获取一次access_token
需要判断ACCESS_TOKEN是否为null,第一次获取的静态变量ACCESS_TOKEN是null,就手动调用getAccessToken方法获取access_token

    @Scheduled(cron = "* * 0/2 * * ?")//定时器Quartz,表示两个小时获取执行一次这个方法,这个是关键(启动类上还要有个注解@EnableScheduling)
    public void getAccessToken() {
//        System.out.println(1);
        //替换变量appid和APPSECRET
        String requestUrl = AccessTokenCommon.ACCESS_TOKEN_URL.replace("APPID", AccessTokenCommon.APPID).replace("APPSECRET", AccessTokenCommon.APPSECRET);
        
        //使用微信工具类发送GET请求,这里"GET"要大写 ,获取到JSONObject类型
        JsonObject jsonObject = WeixinUtil.httpRequest(requestUrl, "GET", null);
        //获取accexx_token
        AccessTokenCommon.ACCESS_TOKEN = jsonObject.getString("access_token");
        System.out.println(AccessTokenCommon.ACCESS_TOKEN );
    }

第二种方式:存在redis中

@Component
public class RedisUtil {
    
    @Autowired
    private RedisTemplate<String,String> redisTemplate;
    
    JSONObject jsonObject = null;

/**
 * @Description  :
 * @author       : wc
 * @param        : access_token的获取第二种方式
 * 获取access_token,如果redis里有,就直接返回
 * 没有就调用getAccessToken获取,再存储到redis中,设置过期时间2小时
 * @CreateDate    :  2020/8/6 17:20
 * @exception    :
 * @return       :
 */
    public String getAccess_token(){
        //查看access_token是否在redis中是否存在
        AccessTokenCommon.ACCESS_TOKEN  = redisTemplate.opsForValue().get("access_token_redis");
        
        //存在,返回access_token; 
        if (AccessTokenCommon.ACCESS_TOKEN !=null){
            return AccessTokenCommon.ACCESS_TOKEN ;
        }else {// 不存在重新调用获取access_token方法,获取,再存入redis中
            AccessTokenCommon.ACCESS_TOKEN  = getAccessToken();
            redisTemplate.opsForValue().set("access_token_redis",AccessTokenCommon.ACCESS_TOKEN ,2, TimeUnit.HOURS);
            return AccessTokenCommon.ACCESS_TOKEN ;
        }
    }
    
	//获取access_tokne方法
    public String getAccessToken() {
        String requestUrl = AccessTokenCommon.ACCESS_TOKEN_URL.replace("APPID", AccessTokenCommon.APPID).replace("APPSECRET", AccessTokenCommon.APPSECRET);
        jsonObject = WeixinUtil.httpRequest(requestUrl, "GET", null);
        AccessTokenCommon.ACCESS_TOKEN  = jsonObject.getString("access_token");
        System.out.println(AccessTokenCommon.ACCESS_TOKEN );
        return AccessTokenCommon.ACCESS_TOKEN ;
    }
}

添加redis依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

application.yml文件配置

spring:
  redis:
    host: 192.168.192.131 #这是单个redis 虚拟机中运行
    port: 6379 #端口号
    password: 1234 #密码
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: 1000
      shutdown-timeout: 100

RedisConfig.java 工具类

package com.yfl.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;

import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.lang.reflect.Method;

/**
 * @ClassName RedisConfig
 * @Description TODO
 * @Author guoweixin
 * @Version 1.0
 */
@Configuration
public class RedisConfig extends CachingConfigurerSupport {

    /**
     * 自定义缓存key的生成策略。默认的生成策略是看不懂的(乱码内容) 通过Spring 的依赖注入特性进行自定义的配置注入并且此类是一个配置类可以更多程度的自定义配置
     *
     * @return
     */
    @Bean
    @Override
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                StringBuilder sb = new StringBuilder();
                sb.append(target.getClass().getName());
                sb.append(method.getName());
                for (Object obj : params) {
                    sb.append(obj.toString());
                }

                return sb.toString();
            }
        };
    }

    /**
     * 缓存配置管理器
     */
    @Bean
    public CacheManager cacheManager(LettuceConnectionFactory factory) {
        //以锁写入的方式创建RedisCacheWriter对象
        RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(factory);
        //创建默认缓存配置对象
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
        RedisCacheManager cacheManager = new RedisCacheManager(writer, config);
        return cacheManager;
    }



    @Bean
    public RedisTemplate<String,Object> redisTemplate(LettuceConnectionFactory factory){
        RedisTemplate<String,Object> template = new RedisTemplate <>();


        template.setConnectionFactory(factory);


        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        // 在使用注解@Bean返回RedisTemplate的时候,同时配置hashKey与hashValue的序列化方式。
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);

        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }

}

第三种方式:线程

AccessTokenThreadUtil 循环获取access_token,每次调用都会休眠2小时;
AccessTokenListener监听器用于启动AccessTokenThreadUtil线程

/**
*继承线程
*/
public class AccessTokenThreadUtil extends Thread {

    JSONObject jsonObject = null;
    String access_token = null;
    @Override
    public void run() {
        while (true){
            this.getAccessToken();//调用方法获取access_token
            try {
                Thread.sleep(7200000);//休眠2小时
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

	//获取access_tokne方法
    public void getAccessToken() {
//        System.out.println(1);
        String requestUrl = AccessTokenCommon.ACCESS_TOKEN_URL.replace("APPID", AccessTokenCommon.APPID).replace("APPSECRET", AccessTokenCommon.APPSECRET);
        jsonObject = WeixinUtil.httpRequest(requestUrl, "GET", null);
        AccessTokenCommon.ACCESS_TOKEN  = jsonObject.getString("access_token");
        System.out.println(AccessTokenCommon.ACCESS_TOKEN );
    }
}
/**
*监听器,在监听器中启动线程
*/
//@Component
public class AccessTokenListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        new AccessTokenThreadUtil().start();
        System.out.println("我的servlet开启了");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("我的servlet关闭了");
    }
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值