demo:https://github.com/wenrongyao/wechat-demo
摘要:access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。
公众平台的API调用所需的access_token的使用及生成方式说明:
01、建议公众号开发者使用中控服务器统一获取和刷新Access_token,其他业务逻辑服务器所使用的access_token均来自于该中控服务器,不应该各自去刷新,否则容易造成冲突,导致access_token覆盖而影响业务;
02、目前Access_token的有效期通过返回的expire_in来传达,目前是7200秒之内的值。中控服务器需要根据这个有效时间提前去刷新新access_token。在刷新过程中,中控服务器可对外继续输出的老access_token,此时公众平台后台会保证在5分钟内,新老access_token都可用,这保证了第三方业务的平滑过渡;
03、Access_token的有效时间可能会在未来有调整,所以中控服务器不仅需要内部定时主动刷新,还需要提供被动刷新access_token的接口,这样便于业务服务器在API调用获知access_token已超时的情况下,可以触发access_token的刷新流程。
2、基本流程
注:在项目启动的时候获取access_token(任何在项目启动时会触发的都可以,例如监听器),获取逻辑:根据appid和appSecret获取accessToken,判断是否为空,为空3秒重新获取一次(以防网络问题,获取三次),不空则90分钟获取一次,每次获取的access_token,放在一次整个项目都可以访问的池子中,可以使用静态变量,也可以使用缓存,根据自己的实际需求选择就可以。
2.1 具体实现
获取accessToken:AccessTokenThread,这个类主要是用于获取access_token,其中实际获取acctoken的部分单独拎出来,以便其它地方手动调用。
import com.wechat.constant.Constant;
import com.wechat.util.DateUtil;
import com.wechat.util.GsonUtil;
import com.wechat.util.HttpRequest;
import com.wechat.util.LogUtil;
import org.springframework.util.StringUtils;
import java.util.Date;
import java.util.Map;
/**
* accessToken线程类
*
* @author WRY
*/
public class AccessTokenThread implements Runnable {
// 微信获取accessToken接口
private static final String ACCESSTOKENURL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appId}&secret={appSecret}";
// 当accessToken获取不成功时重试次数
private static Integer RETRY_TIMES = 3;
public void run() {
int retryTimes = 0;
while (true) {
String accessToken = getAccessToken();
if (!StringUtils.isEmpty(accessToken)) {
Constant.ACCESS_TOKEN = accessToken;
try {
// 90分钟
Thread.sleep(90 * 60 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
retryTimes = 0;
} else {
if (retryTimes >= RETRY_TIMES) {
break;
}
retryTimes += 1;
try {
Thread.sleep(3 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 获取access_Token
*
* @return
*/
public static String getAccessToken() {
String url = ACCESSTOKENURL.replace("{appId}", Constant.WechatAccount.APPID).replace("{appSecret}", Constant.WechatAccount.APPSECRET);
String accessTokenJsonStr = HttpRequest.get(url, null, false);
Map<String, String> accessTokenMap = GsonUtil.fromJson(accessTokenJsonStr, Map.class);
String accessToken = null;
if (null != accessTokenMap && !accessTokenMap.isEmpty()) {
accessToken = accessTokenMap.get("access_token");
if (!StringUtils.isEmpty(accessToken)) {
LogUtil.info("时间:" + DateUtil.getDateStr(new Date()) + ";成功获取accessToken;值为:" + accessToken);
}
}
if (StringUtils.isEmpty(accessToken)) {
String errCode = null;
String errMsg = null;
try {
errCode = accessTokenMap.get("errcode");
errMsg = accessTokenMap.get("errmsg");
} catch (Exception e) {
}
LogUtil.info("时间:" + DateUtil.getDateStr(new Date()) + ";获取accessToken失败;errCode为:" + errCode + ";errMsg" + errMsg);
}
return accessToken;
}
}
其中appid和appsercret是自己公众号的两个参数替换一下即可。我是用静态的变量存放数据的,这个静态的数据在整个工程中是有效的(注:自己用junit普通单元测试或main方法测试是取不到这个值的,应为静态变量的作用域的原因)。
2.2、有了上面的工具,就可以获取access_token了,接下来就是找个合适时机启动这个线程即可。这边使用监听器,在servlet容器创建的时候获取。代码如下:
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
* 监听器
* @author WRY
*
*/
public class AccessTokenlistener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
// 启动accessToken获取线程
new Thread(new AccessTokenThread()).start();
}
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("监听器销毁ֹ");
}
}
2.3 配置监听器
在web.xml中配置监听器
<!-- 获取accessToken的监听器 -->
<listener>
<listener-class>com.wechat.common.accesstoken.AccessTokenlistener</listener-class>
</listener>
springboot配置参考:https://blog.csdn.net/wrongyao/article/details/85702188
好了上述就可以实现在项目启动的时候,获取access_token的值,并且每个90分钟自动获取。确保每次获取的值都是有效的。