Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import javax.net.ssl.SSLContext;
import java.io.File;
import java.util.concurrent.locks.Lock;

/**
* 微信客户端配置存储
Expand All @@ -15,6 +16,8 @@ public interface WxMpConfigStorage {

String getAccessToken();

Lock getAccessTokenLock();

boolean isAccessTokenExpired();

/**
Expand All @@ -37,6 +40,8 @@ public interface WxMpConfigStorage {

String getJsapiTicket();

Lock getJsapiTicketLock();

boolean isJsapiTicketExpired();

/**
Expand All @@ -53,6 +58,8 @@ public interface WxMpConfigStorage {

String getCardApiTicket();

Lock getCardApiTicketLock();

boolean isCardApiTicketExpired();

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import javax.net.ssl.SSLContext;
import java.io.File;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
* 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化
Expand Down Expand Up @@ -36,6 +38,10 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
protected volatile String cardApiTicket;
protected volatile long cardApiTicketExpiresTime;

protected Lock accessTokenLock = new ReentrantLock();
protected Lock jsapiTicketLock = new ReentrantLock();
protected Lock cardApiTicketLock = new ReentrantLock();

/**
* 临时文件目录
*/
Expand All @@ -50,6 +56,11 @@ public String getAccessToken() {
return this.accessToken;
}

@Override
public Lock getAccessTokenLock() {
return this.accessTokenLock;
}

@Override
public boolean isAccessTokenExpired() {
return System.currentTimeMillis() > this.expiresTime;
Expand All @@ -76,6 +87,11 @@ public String getJsapiTicket() {
return this.jsapiTicket;
}

@Override
public Lock getJsapiTicketLock() {
return this.jsapiTicketLock;
}

public void setJsapiTicket(String jsapiTicket) {
this.jsapiTicket = jsapiTicket;
}
Expand Down Expand Up @@ -113,6 +129,11 @@ public String getCardApiTicket() {
return this.cardApiTicket;
}

@Override
public Lock getCardApiTicketLock() {
return this.cardApiTicketLock;
}

@Override
public boolean isCardApiTicketExpired() {
return System.currentTimeMillis() > this.cardApiTicketExpiresTime;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package me.chanjar.weixin.mp.api.impl;

import java.util.Arrays;
import java.util.concurrent.locks.Lock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -29,11 +30,6 @@ public class WxMpCardServiceImpl implements WxMpCardService {

private final Logger log = LoggerFactory.getLogger(WxMpCardServiceImpl.class);

/**
* 全局的是否正在刷新卡券api_ticket的锁
*/
private final Object globalCardApiTicketRefreshLock = new Object();

private WxMpService wxMpService;

public WxMpCardServiceImpl(WxMpService wxMpService) {
Expand Down Expand Up @@ -66,21 +62,25 @@ public String getCardApiTicket() throws WxErrorException {
*/
@Override
public String getCardApiTicket(boolean forceRefresh) throws WxErrorException {
if (forceRefresh) {
this.wxMpService.getWxMpConfigStorage().expireCardApiTicket();
}
if (this.wxMpService.getWxMpConfigStorage().isCardApiTicketExpired()) {
synchronized (this.globalCardApiTicketRefreshLock) {
if (this.wxMpService.getWxMpConfigStorage().isCardApiTicketExpired()) {
String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card";
String responseContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null);
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
String cardApiTicket = tmpJsonObject.get("ticket").getAsString();
int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
this.wxMpService.getWxMpConfigStorage().updateCardApiTicket(cardApiTicket, expiresInSeconds);
}
Lock lock = wxMpService.getWxMpConfigStorage().getCardApiTicketLock();
try {
lock.lock();

if (forceRefresh) {
this.wxMpService.getWxMpConfigStorage().expireCardApiTicket();
}

if (this.wxMpService.getWxMpConfigStorage().isCardApiTicketExpired()) {
String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card";
String responseContent = this.wxMpService.execute(new SimpleGetRequestExecutor(), url, null);
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
String cardApiTicket = tmpJsonObject.get("ticket").getAsString();
int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
this.wxMpService.getWxMpConfigStorage().updateCardApiTicket(cardApiTicket, expiresInSeconds);
}
} finally {
lock.unlock();
}
return this.wxMpService.getWxMpConfigStorage().getCardApiTicket();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,14 @@
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.concurrent.locks.Lock;

public class WxMpServiceImpl implements WxMpService {

private static final JsonParser JSON_PARSER = new JsonParser();

protected final Logger log = LoggerFactory.getLogger(this.getClass());

/**
* 全局的是否正在刷新access token的锁
*/
private final Object globalAccessTokenRefreshLock = new Object();

/**
* 全局的是否正在刷新jsapi_ticket的锁
*/
private final Object globalJsapiTicketRefreshLock = new Object();

private WxMpConfigStorage configStorage;

private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this);
Expand Down Expand Up @@ -98,39 +89,42 @@ public String getAccessToken() throws WxErrorException {

@Override
public String getAccessToken(boolean forceRefresh) throws WxErrorException {
if (forceRefresh) {
this.configStorage.expireAccessToken();
}
Lock lock = configStorage.getAccessTokenLock();
try {
lock.lock();

if (this.configStorage.isAccessTokenExpired()) {
synchronized (this.globalAccessTokenRefreshLock) {
if (this.configStorage.isAccessTokenExpired()) {
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" +
"&appid=" + this.configStorage.getAppId() + "&secret="
+ this.configStorage.getSecret();
try {
HttpGet httpGet = new HttpGet(url);
if (this.httpProxy != null) {
RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy).build();
httpGet.setConfig(config);
}
try (CloseableHttpResponse response = getHttpclient().execute(httpGet)) {
String resultContent = new BasicResponseHandler().handleResponse(response);
WxError error = WxError.fromJson(resultContent);
if (error.getErrorCode() != 0) {
throw new WxErrorException(error);
}
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
this.configStorage.updateAccessToken(accessToken.getAccessToken(),
accessToken.getExpiresIn());
}finally {
httpGet.releaseConnection();
if (forceRefresh) {
this.configStorage.expireAccessToken();
}

if (this.configStorage.isAccessTokenExpired()) {
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" +
"&appid=" + this.configStorage.getAppId() + "&secret="
+ this.configStorage.getSecret();
try {
HttpGet httpGet = new HttpGet(url);
if (this.httpProxy != null) {
RequestConfig config = RequestConfig.custom().setProxy(this.httpProxy).build();
httpGet.setConfig(config);
}
try (CloseableHttpResponse response = getHttpclient().execute(httpGet)) {
String resultContent = new BasicResponseHandler().handleResponse(response);
WxError error = WxError.fromJson(resultContent);
if (error.getErrorCode() != 0) {
throw new WxErrorException(error);
}
} catch (IOException e) {
throw new RuntimeException(e);
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
this.configStorage.updateAccessToken(accessToken.getAccessToken(),
accessToken.getExpiresIn());
}finally {
httpGet.releaseConnection();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
} finally {
lock.unlock();
}
return this.configStorage.getAccessToken();
}
Expand All @@ -142,22 +136,25 @@ public String getJsapiTicket() throws WxErrorException {

@Override
public String getJsapiTicket(boolean forceRefresh) throws WxErrorException {
if (forceRefresh) {
this.configStorage.expireJsapiTicket();
}
Lock lock = configStorage.getJsapiTicketLock();
try {
lock.lock();

if (this.configStorage.isJsapiTicketExpired()) {
synchronized (this.globalJsapiTicketRefreshLock) {
if (this.configStorage.isJsapiTicketExpired()) {
String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi";
String responseContent = execute(new SimpleGetRequestExecutor(), url, null);
JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent);
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
String jsapiTicket = tmpJsonObject.get("ticket").getAsString();
int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
this.configStorage.updateJsapiTicket(jsapiTicket, expiresInSeconds);
}
if (forceRefresh) {
this.configStorage.expireJsapiTicket();
}

if (this.configStorage.isJsapiTicketExpired()) {
String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi";
String responseContent = execute(new SimpleGetRequestExecutor(), url, null);
JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent);
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
String jsapiTicket = tmpJsonObject.get("ticket").getAsString();
int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
this.configStorage.updateJsapiTicket(jsapiTicket, expiresInSeconds);
}
} finally {
lock.unlock();
}
return this.configStorage.getJsapiTicket();
}
Expand Down