AccessTokenApi.java
4.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/**
* Copyright (c) 2011-2014, James Zhan 詹波 (jfinal@126.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
*/
package com.jfinal.weixin.sdk.api;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.jfinal.weixin.sdk.cache.IAccessTokenCache;
import com.jfinal.weixin.sdk.kit.ParaMap;
import com.jfinal.weixin.sdk.utils.HttpUtils;
import com.jfinal.weixin.sdk.utils.RetryUtils;
import java.util.Map;
import java.util.concurrent.Callable;
/**
* 认证并获取 access_token API
* http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96access_token
*
* AccessToken默认存储于内存中,可设置存储于redis或者实现IAccessTokenCache到数据库中实现分布式可用
*
* 具体配置:
* <pre>
* ApiConfigKit.setAccessTokenCache(new RedisAccessTokenCache());
* </pre>
*/
public class AccessTokenApi {
// "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
private static String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential";
/**
* 从缓存中获取 access token,如果未取到或者 access token 不可用则先更新再获取
* @return AccessToken accessToken
*/
public static AccessToken getAccessToken() {
ApiConfig ac = ApiConfigKit.getApiConfig();
AccessToken result = getAvailableAccessToken(ac);
if (result != null) {
return result;
}
return refreshAccessTokenIfNecessary(ac);
}
private static AccessToken getAvailableAccessToken(ApiConfig ac) {
// 利用 appId 与 accessToken 建立关联,支持多账户
IAccessTokenCache accessTokenCache = ApiConfigKit.getAccessTokenCache();
String accessTokenJson = accessTokenCache.get(ac.getAppId());
if (StrKit.notBlank(accessTokenJson)) {
AccessToken result = new AccessToken(accessTokenJson);
if (result != null && result.isAvailable()) {
return result;
}
}
return null;
}
/**
* 直接获取 accessToken 字符串,方便使用
* @return String accessToken
*/
public static String getAccessTokenStr() {
return getAccessToken().getAccessToken();
}
/**
* synchronized 配合再次获取 token 并检测可用性,防止多线程重复刷新 token 值
*/
private static synchronized AccessToken refreshAccessTokenIfNecessary(ApiConfig ac) {
AccessToken result = getAvailableAccessToken(ac);
if (result != null) {
return result;
}
return refreshAccessToken(ac);
}
/**
* 无条件强制更新 access token 值,不再对 cache 中的 token 进行判断
* @return AccessToken
*/
public static AccessToken refreshAccessToken() {
return refreshAccessToken(ApiConfigKit.getApiConfig());
}
/**
* 无条件强制更新 access token 值,不再对 cache 中的 token 进行判断
* @param ac ApiConfig
* @return AccessToken
*/
public static AccessToken refreshAccessToken(ApiConfig ac) {
String appId = ac.getAppId();
String appSecret = ac.getAppSecret();
final Map<String, String> queryParas = ParaMap.create("appid", appId).put("secret", appSecret).getData();
// 最多三次请求
AccessToken result = RetryUtils.retryOnException(3, new Callable<AccessToken>() {
@Override
public AccessToken call() throws Exception {
String json = HttpUtils.get(url, queryParas);
return new AccessToken(json);
}
});
// 三次请求如果仍然返回了不可用的 access token 仍然 put 进去,便于上层通过 AccessToken 中的属性判断底层的情况
if (null != result) {
// 利用 appId 与 accessToken 建立关联,支持多账户
IAccessTokenCache accessTokenCache = ApiConfigKit.getAccessTokenCache();
accessTokenCache.set(ac.getAppId(), result.getCacheJson());
}
return result;
}
public static void main(String[] args) {
PropKit.use("a_little_config.txt");
ApiConfig apiConfig = new ApiConfig();
apiConfig.setAppId(PropKit.get("appId"));
apiConfig.setAppSecret(PropKit.get("appSecret"));
ApiConfigKit.putApiConfig(apiConfig);
AccessToken accessToken = AccessTokenApi.getAccessToken();
System.out.println(accessToken.getAccessToken());
System.out.println(AccessTokenApi.getAccessTokenStr());
}
}