Skip to content

Commit 0fa17f4

Browse files
committed
为四个WxCpService实现类添加getMsgAuditAccessToken方法
- 在WxCpServiceApacheHttpClientImpl中实现getMsgAuditAccessToken方法 - 在WxCpServiceHttpComponentsImpl中实现getMsgAuditAccessToken方法 - 在WxCpServiceOkHttpImpl中实现getMsgAuditAccessToken方法,使用try-with-resources正确关闭Response - 在WxCpServiceJoddHttpImpl中实现getMsgAuditAccessToken方法 所有实现遵循以下设计: - 使用Lock机制和双重检查确保线程安全 - 使用会话存档secret(msgAuditSecret)获取access token - 将token存储到updateMsgAuditAccessToken() - 当msgAuditSecret未配置时抛出WxErrorException - 保持各实现类原有的HTTP客户端使用风格和代理支持 新增单元测试WxCpServiceGetMsgAuditAccessTokenTest验证实现正确性, 包括正常场景和异常场景(secret未配置或为空)的测试。
1 parent 4398b34 commit 0fa17f4

12 files changed

+556
-3
lines changed

weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,19 @@ public interface WxCpService extends WxService {
5757
*/
5858
String getAccessToken(boolean forceRefresh) throws WxErrorException;
5959

60+
/**
61+
* <pre>
62+
* 获取会话存档access_token,本方法线程安全
63+
* 会话存档相关接口需要使用会话存档secret获取单独的access_token
64+
* 详情请见: https://developer.work.weixin.qq.com/document/path/91782
65+
* </pre>
66+
*
67+
* @param forceRefresh 强制刷新
68+
* @return 会话存档专用的access token
69+
* @throws WxErrorException the wx error exception
70+
*/
71+
String getMsgAuditAccessToken(boolean forceRefresh) throws WxErrorException;
72+
6073
/**
6174
* 获得jsapi_ticket,不强制刷新jsapi_ticket
6275
*

weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMsgAuditServiceImpl.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -297,30 +297,48 @@ public void getMediaFile(@NonNull long sdk, @NonNull String sdkfileid, String pr
297297

298298
@Override
299299
public List<String> getPermitUserList(Integer type) throws WxErrorException {
300+
// 获取会话存档专用的access token
301+
String msgAuditAccessToken = this.cpService.getMsgAuditAccessToken(false);
300302
final String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(GET_PERMIT_USER_LIST);
303+
// 手动拼接access_token参数
304+
String urlWithToken = apiUrl + (apiUrl.contains("?") ? "&" : "?") + "access_token=" + msgAuditAccessToken;
305+
301306
JsonObject jsonObject = new JsonObject();
302307
if (type != null) {
303308
jsonObject.addProperty("type", type);
304309
}
305-
String responseContent = this.cpService.post(apiUrl, jsonObject.toString());
310+
// 使用不自动添加access token的post方法
311+
String responseContent = this.cpService.postWithoutToken(urlWithToken, jsonObject.toString());
306312
return WxCpGsonBuilder.create().fromJson(GsonParser.parse(responseContent).getAsJsonArray("ids"),
307313
new TypeToken<List<String>>() {
308314
}.getType());
309315
}
310316

311317
@Override
312318
public WxCpGroupChat getGroupChat(@NonNull String roomid) throws WxErrorException {
319+
// 获取会话存档专用的access token
320+
String msgAuditAccessToken = this.cpService.getMsgAuditAccessToken(false);
313321
final String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(GET_GROUP_CHAT);
322+
// 手动拼接access_token参数
323+
String urlWithToken = apiUrl + (apiUrl.contains("?") ? "&" : "?") + "access_token=" + msgAuditAccessToken;
324+
314325
JsonObject jsonObject = new JsonObject();
315326
jsonObject.addProperty("roomid", roomid);
316-
String responseContent = this.cpService.post(apiUrl, jsonObject.toString());
327+
// 使用不自动添加access token的post方法
328+
String responseContent = this.cpService.postWithoutToken(urlWithToken, jsonObject.toString());
317329
return WxCpGroupChat.fromJson(responseContent);
318330
}
319331

320332
@Override
321333
public WxCpAgreeInfo checkSingleAgree(@NonNull WxCpCheckAgreeRequest checkAgreeRequest) throws WxErrorException {
334+
// 获取会话存档专用的access token
335+
String msgAuditAccessToken = this.cpService.getMsgAuditAccessToken(false);
322336
String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(CHECK_SINGLE_AGREE);
323-
String responseContent = this.cpService.post(apiUrl, checkAgreeRequest.toJson());
337+
// 手动拼接access_token参数
338+
String urlWithToken = apiUrl + (apiUrl.contains("?") ? "&" : "?") + "access_token=" + msgAuditAccessToken;
339+
340+
// 使用不自动添加access token的post方法
341+
String responseContent = this.cpService.postWithoutToken(urlWithToken, checkAgreeRequest.toJson());
324342
return WxCpAgreeInfo.fromJson(responseContent);
325343
}
326344

weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.apache.http.impl.client.CloseableHttpClient;
1818

1919
import java.io.IOException;
20+
import java.util.concurrent.locks.Lock;
2021

2122
/**
2223
* The type Wx cp service apache http client.
@@ -74,6 +75,51 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
7475
return this.configStorage.getAccessToken();
7576
}
7677

78+
@Override
79+
public String getMsgAuditAccessToken(boolean forceRefresh) throws WxErrorException {
80+
if (!this.configStorage.isMsgAuditAccessTokenExpired() && !forceRefresh) {
81+
return this.configStorage.getMsgAuditAccessToken();
82+
}
83+
84+
Lock lock = this.configStorage.getMsgAuditAccessTokenLock();
85+
lock.lock();
86+
try {
87+
// 拿到锁之后,再次判断一下最新的token是否过期,避免重刷
88+
if (!this.configStorage.isMsgAuditAccessTokenExpired() && !forceRefresh) {
89+
return this.configStorage.getMsgAuditAccessToken();
90+
}
91+
// 使用会话存档secret获取access_token
92+
String msgAuditSecret = this.configStorage.getMsgAuditSecret();
93+
if (msgAuditSecret == null || msgAuditSecret.trim().isEmpty()) {
94+
throw new WxErrorException("会话存档secret未配置");
95+
}
96+
String url = String.format(this.configStorage.getApiUrl(WxCpApiPathConsts.GET_TOKEN),
97+
this.configStorage.getCorpId(), msgAuditSecret);
98+
99+
try {
100+
HttpGet httpGet = new HttpGet(url);
101+
if (this.httpProxy != null) {
102+
RequestConfig config = RequestConfig.custom()
103+
.setProxy(this.httpProxy).build();
104+
httpGet.setConfig(config);
105+
}
106+
String resultContent = getRequestHttpClient().execute(httpGet, ApacheBasicResponseHandler.INSTANCE);
107+
WxError error = WxError.fromJson(resultContent, WxType.CP);
108+
if (error.getErrorCode() != 0) {
109+
throw new WxErrorException(error);
110+
}
111+
112+
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
113+
this.configStorage.updateMsgAuditAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
114+
} catch (IOException e) {
115+
throw new WxRuntimeException(e);
116+
}
117+
} finally {
118+
lock.unlock();
119+
}
120+
return this.configStorage.getMsgAuditAccessToken();
121+
}
122+
77123
@Override
78124
public void initHttp() {
79125
ApacheHttpClientBuilder apacheHttpClientBuilder = this.configStorage

weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceHttpComponentsImpl.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.apache.hc.core5.http.HttpHost;
1818

1919
import java.io.IOException;
20+
import java.util.concurrent.locks.Lock;
2021

2122
/**
2223
* The type Wx cp service apache http client.
@@ -75,6 +76,51 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
7576
return this.configStorage.getAccessToken();
7677
}
7778

79+
@Override
80+
public String getMsgAuditAccessToken(boolean forceRefresh) throws WxErrorException {
81+
if (!this.configStorage.isMsgAuditAccessTokenExpired() && !forceRefresh) {
82+
return this.configStorage.getMsgAuditAccessToken();
83+
}
84+
85+
Lock lock = this.configStorage.getMsgAuditAccessTokenLock();
86+
lock.lock();
87+
try {
88+
// 拿到锁之后,再次判断一下最新的token是否过期,避免重刷
89+
if (!this.configStorage.isMsgAuditAccessTokenExpired() && !forceRefresh) {
90+
return this.configStorage.getMsgAuditAccessToken();
91+
}
92+
// 使用会话存档secret获取access_token
93+
String msgAuditSecret = this.configStorage.getMsgAuditSecret();
94+
if (msgAuditSecret == null || msgAuditSecret.trim().isEmpty()) {
95+
throw new WxErrorException("会话存档secret未配置");
96+
}
97+
String url = String.format(this.configStorage.getApiUrl(WxCpApiPathConsts.GET_TOKEN),
98+
this.configStorage.getCorpId(), msgAuditSecret);
99+
100+
try {
101+
HttpGet httpGet = new HttpGet(url);
102+
if (this.httpProxy != null) {
103+
RequestConfig config = RequestConfig.custom()
104+
.setProxy(this.httpProxy).build();
105+
httpGet.setConfig(config);
106+
}
107+
String resultContent = getRequestHttpClient().execute(httpGet, BasicResponseHandler.INSTANCE);
108+
WxError error = WxError.fromJson(resultContent, WxType.CP);
109+
if (error.getErrorCode() != 0) {
110+
throw new WxErrorException(error);
111+
}
112+
113+
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
114+
this.configStorage.updateMsgAuditAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
115+
} catch (IOException e) {
116+
throw new WxRuntimeException(e);
117+
}
118+
} finally {
119+
lock.unlock();
120+
}
121+
return this.configStorage.getMsgAuditAccessToken();
122+
}
123+
78124
@Override
79125
public void initHttp() {
80126
HttpComponentsClientBuilder apacheHttpClientBuilder = DefaultHttpComponentsClientBuilder.get();

weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,49 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
7070
return configStorage.getAccessToken();
7171
}
7272

73+
@Override
74+
public String getMsgAuditAccessToken(boolean forceRefresh) throws WxErrorException {
75+
final WxCpConfigStorage configStorage = getWxCpConfigStorage();
76+
if (!configStorage.isMsgAuditAccessTokenExpired() && !forceRefresh) {
77+
return configStorage.getMsgAuditAccessToken();
78+
}
79+
Lock lock = configStorage.getMsgAuditAccessTokenLock();
80+
lock.lock();
81+
try {
82+
// 拿到锁之后,再次判断一下最新的token是否过期,避免重刷
83+
if (!configStorage.isMsgAuditAccessTokenExpired() && !forceRefresh) {
84+
return configStorage.getMsgAuditAccessToken();
85+
}
86+
// 使用会话存档secret获取access_token
87+
String msgAuditSecret = configStorage.getMsgAuditSecret();
88+
if (msgAuditSecret == null || msgAuditSecret.trim().isEmpty()) {
89+
throw new WxErrorException("会话存档secret未配置");
90+
}
91+
String url = String.format(configStorage.getApiUrl(WxCpApiPathConsts.GET_TOKEN),
92+
this.configStorage.getCorpId(), msgAuditSecret);
93+
try {
94+
HttpGet httpGet = new HttpGet(url);
95+
if (getRequestHttpProxy() != null) {
96+
RequestConfig config = RequestConfig.custom().setProxy(getRequestHttpProxy()).build();
97+
httpGet.setConfig(config);
98+
}
99+
String resultContent = getRequestHttpClient().execute(httpGet, ApacheBasicResponseHandler.INSTANCE);
100+
WxError error = WxError.fromJson(resultContent, WxType.CP);
101+
if (error.getErrorCode() != 0) {
102+
throw new WxErrorException(error);
103+
}
104+
105+
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
106+
configStorage.updateMsgAuditAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
107+
} catch (IOException e) {
108+
throw new WxRuntimeException(e);
109+
}
110+
} finally {
111+
lock.unlock();
112+
}
113+
return configStorage.getMsgAuditAccessToken();
114+
}
115+
73116
@Override
74117
public String getAgentJsapiTicket(boolean forceRefresh) throws WxErrorException {
75118
final WxCpConfigStorage configStorage = getWxCpConfigStorage();

weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
1414
import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
1515

16+
import java.util.concurrent.locks.Lock;
17+
1618
/**
1719
* The type Wx cp service jodd http.
1820
*
@@ -63,6 +65,45 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
6365
return this.configStorage.getAccessToken();
6466
}
6567

68+
@Override
69+
public String getMsgAuditAccessToken(boolean forceRefresh) throws WxErrorException {
70+
if (!this.configStorage.isMsgAuditAccessTokenExpired() && !forceRefresh) {
71+
return this.configStorage.getMsgAuditAccessToken();
72+
}
73+
74+
Lock lock = this.configStorage.getMsgAuditAccessTokenLock();
75+
lock.lock();
76+
try {
77+
// 拿到锁之后,再次判断一下最新的token是否过期,避免重刷
78+
if (!this.configStorage.isMsgAuditAccessTokenExpired() && !forceRefresh) {
79+
return this.configStorage.getMsgAuditAccessToken();
80+
}
81+
// 使用会话存档secret获取access_token
82+
String msgAuditSecret = this.configStorage.getMsgAuditSecret();
83+
if (msgAuditSecret == null || msgAuditSecret.trim().isEmpty()) {
84+
throw new WxErrorException("会话存档secret未配置");
85+
}
86+
HttpRequest request = HttpRequest.get(String.format(this.configStorage.getApiUrl(WxCpApiPathConsts.GET_TOKEN),
87+
this.configStorage.getCorpId(), msgAuditSecret));
88+
if (this.httpProxy != null) {
89+
httpClient.useProxy(this.httpProxy);
90+
}
91+
request.withConnectionProvider(httpClient);
92+
HttpResponse response = request.send();
93+
94+
String resultContent = response.bodyText();
95+
WxError error = WxError.fromJson(resultContent, WxType.CP);
96+
if (error.getErrorCode() != 0) {
97+
throw new WxErrorException(error);
98+
}
99+
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
100+
this.configStorage.updateMsgAuditAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
101+
} finally {
102+
lock.unlock();
103+
}
104+
return this.configStorage.getMsgAuditAccessToken();
105+
}
106+
66107
@Override
67108
public void initHttp() {
68109
if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) {

weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import okhttp3.*;
1313

1414
import java.io.IOException;
15+
import java.util.concurrent.locks.Lock;
1516

1617
import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.GET_TOKEN;
1718

@@ -74,6 +75,52 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
7475
return this.configStorage.getAccessToken();
7576
}
7677

78+
@Override
79+
public String getMsgAuditAccessToken(boolean forceRefresh) throws WxErrorException {
80+
if (!this.configStorage.isMsgAuditAccessTokenExpired() && !forceRefresh) {
81+
return this.configStorage.getMsgAuditAccessToken();
82+
}
83+
84+
Lock lock = this.configStorage.getMsgAuditAccessTokenLock();
85+
lock.lock();
86+
try {
87+
// 拿到锁之后,再次判断一下最新的token是否过期,避免重刷
88+
if (!this.configStorage.isMsgAuditAccessTokenExpired() && !forceRefresh) {
89+
return this.configStorage.getMsgAuditAccessToken();
90+
}
91+
// 使用会话存档secret获取access_token
92+
String msgAuditSecret = this.configStorage.getMsgAuditSecret();
93+
if (msgAuditSecret == null || msgAuditSecret.trim().isEmpty()) {
94+
throw new WxErrorException("会话存档secret未配置");
95+
}
96+
//得到httpClient
97+
OkHttpClient client = getRequestHttpClient();
98+
//请求的request
99+
Request request = new Request.Builder()
100+
.url(String.format(this.configStorage.getApiUrl(GET_TOKEN), this.configStorage.getCorpId(),
101+
msgAuditSecret))
102+
.get()
103+
.build();
104+
String resultContent = null;
105+
try (Response response = client.newCall(request).execute()) {
106+
resultContent = response.body().string();
107+
} catch (IOException e) {
108+
log.error(e.getMessage(), e);
109+
}
110+
111+
WxError error = WxError.fromJson(resultContent, WxType.CP);
112+
if (error.getErrorCode() != 0) {
113+
throw new WxErrorException(error);
114+
}
115+
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
116+
this.configStorage.updateMsgAuditAccessToken(accessToken.getAccessToken(),
117+
accessToken.getExpiresIn());
118+
} finally {
119+
lock.unlock();
120+
}
121+
return this.configStorage.getMsgAuditAccessToken();
122+
}
123+
77124
@Override
78125
public void initHttp() {
79126
log.debug("WxCpServiceOkHttpImpl initHttp");

weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,40 @@ public interface WxCpConfigStorage {
265265
*/
266266
String getMsgAuditSecret();
267267

268+
/**
269+
* 获取会话存档的access token
270+
*
271+
* @return msg audit access token
272+
*/
273+
String getMsgAuditAccessToken();
274+
275+
/**
276+
* 获取会话存档access token的锁
277+
*
278+
* @return msg audit access token lock
279+
*/
280+
Lock getMsgAuditAccessTokenLock();
281+
282+
/**
283+
* 检查会话存档access token是否已过期
284+
*
285+
* @return true: 已过期, false: 未过期
286+
*/
287+
boolean isMsgAuditAccessTokenExpired();
288+
289+
/**
290+
* 强制将会话存档access token过期掉
291+
*/
292+
void expireMsgAuditAccessToken();
293+
294+
/**
295+
* 更新会话存档access token
296+
*
297+
* @param accessToken 会话存档access token
298+
* @param expiresInSeconds 过期时间(秒)
299+
*/
300+
void updateMsgAuditAccessToken(String accessToken, int expiresInSeconds);
301+
268302
/**
269303
* 获取会话存档SDK
270304
* 会话存档SDK初始化后有效期为7200秒,无需每次重新初始化

0 commit comments

Comments
 (0)