SpringBoot获取微信公众号(小程序)access_token 使用Redis存储


前言

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

一、导入依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
       <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.73</version>
        </dependency>

二、编写配置

1.personal.yaml配置文件

我的微信小程序ID小程序密匙都放在配置文件中。
在这里插入图片描述
personal.yaml文件放在resources文件夹中

wechat:
  appid: AppID
  secret: AppSecret

2.WeChatBean实体类

@Data
@Component
@PropertySource(value = "classpath:personal.yaml")
@ConfigurationProperties(prefix = "wechat")
public class WeChatBean {

    @Value("${appid}")
    private String appId;

    @Value("${secret}")
    private String secret;
}

3.编写RestTemplateConfig

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate (ClientHttpRequestFactory clientHttpRequestFactory) {
        return new RestTemplate(clientHttpRequestFactory);
    }

    @Bean
    public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setConnectTimeout(15000);
        factory.setReadTimeout(5000);
        return factory;
    }

}

4. 开启定时任务

在主启动类中开始定时任务。

@EnableAsync
@MapperScan("top.ddandang.*.mapper")
@SpringBootApplication
@EnableScheduling
public class BlogBackApplication {
    public static void main(String[] args) {
        SpringApplication.run(BlogBackApplication.class, args);
    }
}

三、实现生成和存储access_token

使用定时任务每1小时50分钟发送一次请求,然后在Redis中设置有效时间为1小时55分钟,这样可以保证不会出现不能用的情况,也不会出现Redis中不存在此Key值(除非Redis服务崩了)

1.基本介绍

接口示例:

https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

RestTemplate带参发送Get请求两种方式。

方式一:

 		String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=你的AppID&secret=你的App密匙";
        ResponseEntity<String> forObject = restTemplate.getForEntity(url, String.class);

方式二:

        String url = "https://api.weixin.qq.com/cgi-bin/token";
        // 这里的参数要和下面的Map Key值对应
        String path = "?grant_type={grant_type}&appid={appid}&secret={secret}";
        Map<String, String> params = new HashMap<>(3);
        params.put("grant_type", "client_credential");
        params.put("appid", 你的AppID);
        params.put("secret", 你的App密匙);
        ResponseEntity<String> forObject = restTemplate.getForEntity(url + path, String.class, params);

2.编写Server层—WeChatServerImpl

package top.ddandang.blog.service.impl;

import com.alibaba.fastjson.JSONObject;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import top.ddandang.blog.bean.WeChatBean;
import top.ddandang.blog.service.WeChatServer;
import top.ddandang.blog.utils.RedisUtil;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *
 * </p>
 *
 * @author: D
 * @since: 2020/9/6
 * @version: 1
 */
@Service
public class WeChatServerImpl implements WeChatServer {

    @Resource
    WeChatBean weChatBean;

    @Resource
    RestTemplate restTemplate;

    @Resource
    RedisUtil redisUtil;

    /**
     * redis中存放access_token的key值
     */
    private final static String ACCESS_TOKEN_KEY = "accessToken";

    /**
     * redis中存放获取失败的错误信息的key值
     */
    private final static String ERROR_KEY = "accessToken";

    @Scheduled(initialDelay = 10000,fixedRate = 6600000)
    @Override
    public void creatAccessToken() {
        String url = "https://api.weixin.qq.com/cgi-bin/token";
        String path = "?grant_type={grant_type}&appid={appid}&secret={secret}";
        Map<String, String> params = new HashMap<>(3);
        params.put("grant_type", "client_credential");
        params.put("appid", weChatBean.getAppId());
        params.put("secret", weChatBean.getSecret());
        
        ResponseEntity<String> forObject = restTemplate.getForEntity(url + path, String.class, params);
        
        System.out.println(forObject.getBody());
        
        JSONObject jsonObject = JSONObject.parseObject(forObject.getBody());
        
        String accessToken = jsonObject.getString("access_token");
        
        System.out.println(accessToken);
        // accessToken获取成功
        if (accessToken != null) {
            //有效期设置1小时55分钟
            redisUtil.set(ACCESS_TOKEN_KEY, accessToken, 115, TimeUnit.MINUTES);
        } else {
            redisUtil.set(ERROR_KEY, forObject.getBody());
        }
    }

    @Override
    public String getAccessToken() {
        //这大概率不会运行 除非redis连接失败或者蹦了
        if (!redisUtil.hasKey(ACCESS_TOKEN_KEY)) {
            throw new RuntimeException("获取失败,请稍后重试");
        }
        return (String) redisUtil.get(ACCESS_TOKEN_KEY);
    }
}

3.编写Controller层—WeChatController

@RestController
@RequestMapping("/we_chat")
public class WeChatController {

    @Resource
    WeChatServer weChatServer;

    @GetMapping("/getAccessToken")
    public GlobalResponse getAccessToken() {
        try {
            String accessToken = weChatServer.getAccessToken();
            return GlobalResponse.success().data("accessToken", accessToken);
        } catch (RuntimeException e) {
            return GlobalResponse.failed().message("获取失败,请稍后再试!");
        }
    }
}

4.简单解析

//单位毫秒
@Scheduled(initialDelay = 10000,fixedRate = 6600000)

项目运行的时候然后延迟10秒第一次执行这个方法,然后之后每隔1小时50分钟再次执行这方法。

ResponseEntity<String> forObject = restTemplate.getForEntity(url + path, String.class, params);
System.out.println(forObject.getBody());

getForEntity:获取全部的响应内容,包含响应头,响应码,和响应体,这里也可以直接换成getForObject只获取响应体。
响应体:
在这里插入图片描述
在这里插入图片描述

返回的响应体是一个Json格式的字符串这里使用阿里巴巴的fastjson进行转换。

String accessToken = jsonObject.getString(“access_token”);

jsonObject.getString(“access_token”)可以获取到access_token的数据,如果是错误返回的话这个就是为null后面只需要进行判断accessToken为null就是错误返回了。

将数据存放到Redis中:

这里存放时间设置为1小时55分钟,因为有效期为2小时,然后方法的自动调用为每隔1小时50分钟进行调用。这里存放错误信息只是为了方便进行在Redis中进行查看。
这里使用了Redis工具类:可以参考:Redis工具类

        // accessToken获取成功
        if (accessToken != null) {
            //有效期设置1小时55分钟
            redisUtil.set(ACCESS_TOKEN_KEY, accessToken, 115, TimeUnit.MINUTES);
        } else {
            redisUtil.set(ERROR_KEY, forObject.getBody());
        }

总结

基本上个人的密匙之类的都放在一个配置文件中,不会直接写到类里面,花了近两个小时进行编写有什么不足之处欢迎进行交流,有什么问题也可以直接在讨论区提问。

猜你喜欢

转载自blog.csdn.net/d875708765/article/details/108434912