diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java index fb2ef3b9b7..ec7423a8b8 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java @@ -22,6 +22,8 @@ public interface WxMaService extends WxService { * 获取access_token. */ String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; + String GET_STABLE_ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/stable_token"; + /** * The constant JSCODE_TO_SESSION_URL. diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java index 4cff1bf16b..2080c227fc 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java @@ -174,7 +174,13 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { return this.getWxMaConfig().getAccessToken(); } } while (!locked); - String response = doGetAccessTokenRequest(); + + String response; + if (getWxMaConfig().isStableAccessToken()) { + response = doGetStableAccessTokenRequest(forceRefresh); + } else { + response = doGetAccessTokenRequest(); + } return extractAccessToken(response); } catch (IOException | InterruptedException e) { throw new WxRuntimeException(e); @@ -193,6 +199,15 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { */ protected abstract String doGetAccessTokenRequest() throws IOException; + + /** + * 通过网络请求获取稳定版接口调用凭据 + * + * @return . + * @throws IOException . + */ + protected abstract String doGetStableAccessTokenRequest(boolean forceRefresh) throws IOException; + @Override public String get(String url, String queryParam) throws WxErrorException { return execute(SimpleGetRequestExecutor.create(this), url, queryParam); diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceHttpClientImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceHttpClientImpl.java index f0816fc85a..7b1ea3e96b 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceHttpClientImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceHttpClientImpl.java @@ -1,6 +1,7 @@ package cn.binarywang.wx.miniapp.api.impl; import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaStableAccessTokenRequest; import cn.binarywang.wx.miniapp.config.WxMaConfig; import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.util.http.HttpType; @@ -11,6 +12,9 @@ import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.impl.client.CloseableHttpClient; @@ -93,4 +97,40 @@ protected String doGetAccessTokenRequest() throws IOException { } } + @Override + protected String doGetStableAccessTokenRequest(boolean forceRefresh) throws IOException { + String url = StringUtils.isNotEmpty(this.getWxMaConfig().getAccessTokenUrl()) ? + this.getWxMaConfig().getAccessTokenUrl() : StringUtils.isNotEmpty(this.getWxMaConfig().getApiHostUrl()) ? + GET_STABLE_ACCESS_TOKEN.replace("https://api.weixin.qq.com", this.getWxMaConfig().getApiHostUrl()) : + GET_STABLE_ACCESS_TOKEN; + + HttpPost httpPost = null; + CloseableHttpResponse response = null; + try { + httpPost = new HttpPost(url); + if (this.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + WxMaStableAccessTokenRequest wxMaAccessTokenRequest = new WxMaStableAccessTokenRequest(); + wxMaAccessTokenRequest.setAppid(this.getWxMaConfig().getAppid()); + wxMaAccessTokenRequest.setSecret(this.getWxMaConfig().getSecret()); + wxMaAccessTokenRequest.setGrantType("client_credential"); + wxMaAccessTokenRequest.setForceRefresh(forceRefresh); + httpPost.setEntity(new StringEntity(wxMaAccessTokenRequest.toJson(), ContentType.APPLICATION_JSON)); + response = getRequestHttpClient().execute(httpPost); + return new BasicResponseHandler().handleResponse(response); + } finally { + if (httpPost != null) { + httpPost.releaseConnection(); + } + if (response != null) { + try { + response.close(); + } catch (IOException e) { + } + } + } + } + } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceJoddHttpImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceJoddHttpImpl.java index f14d8cd6dd..d2037a0732 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceJoddHttpImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceJoddHttpImpl.java @@ -1,15 +1,18 @@ package cn.binarywang.wx.miniapp.api.impl; import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaStableAccessTokenRequest; import cn.binarywang.wx.miniapp.config.WxMaConfig; import jodd.http.HttpConnectionProvider; import jodd.http.HttpRequest; import jodd.http.ProxyInfo; import jodd.http.net.SocketHttpConnectionProvider; +import jodd.net.MimeTypes; import me.chanjar.weixin.common.util.http.HttpType; import org.apache.commons.lang3.StringUtils; import java.io.IOException; +import java.nio.charset.StandardCharsets; /** * jodd-http方式实现. @@ -62,4 +65,30 @@ protected String doGetAccessTokenRequest() throws IOException { return request.send().bodyText(); } + @Override + protected String doGetStableAccessTokenRequest(boolean forceRefresh) throws IOException { + + String url = StringUtils.isNotEmpty(this.getWxMaConfig().getAccessTokenUrl()) ? + this.getWxMaConfig().getAccessTokenUrl() : StringUtils.isNotEmpty(this.getWxMaConfig().getApiHostUrl()) ? + GET_STABLE_ACCESS_TOKEN.replace("https://api.weixin.qq.com", this.getWxMaConfig().getApiHostUrl()) : + GET_STABLE_ACCESS_TOKEN; + + WxMaStableAccessTokenRequest wxMaAccessTokenRequest = new WxMaStableAccessTokenRequest(); + wxMaAccessTokenRequest.setAppid(this.getWxMaConfig().getAppid()); + wxMaAccessTokenRequest.setSecret(this.getWxMaConfig().getSecret()); + wxMaAccessTokenRequest.setGrantType("client_credential"); + wxMaAccessTokenRequest.setForceRefresh(forceRefresh); + + HttpRequest request = HttpRequest.post(url) + .contentType(MimeTypes.MIME_APPLICATION_JSON, StandardCharsets.UTF_8.name()) + .body(wxMaAccessTokenRequest.toJson()); + if (this.getRequestHttpProxy() != null) { + SocketHttpConnectionProvider provider = new SocketHttpConnectionProvider(); + provider.useProxy(getRequestHttpProxy()); + + request.withConnectionProvider(provider); + } + return request.send().bodyText(); + } + } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceOkHttpImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceOkHttpImpl.java index 8580c62611..ff78a6984a 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceOkHttpImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceOkHttpImpl.java @@ -1,6 +1,7 @@ package cn.binarywang.wx.miniapp.api.impl; import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaStableAccessTokenRequest; import cn.binarywang.wx.miniapp.config.WxMaConfig; import me.chanjar.weixin.common.util.http.HttpType; import me.chanjar.weixin.common.util.http.okhttp.DefaultOkHttpClientBuilder; @@ -74,4 +75,22 @@ protected String doGetAccessTokenRequest() throws IOException { return Objects.requireNonNull(response.body()).string(); } } + + @Override + protected String doGetStableAccessTokenRequest(boolean forceRefresh) throws IOException { + String url = StringUtils.isNotEmpty(this.getWxMaConfig().getAccessTokenUrl()) ? + this.getWxMaConfig().getAccessTokenUrl() : StringUtils.isNotEmpty(this.getWxMaConfig().getApiHostUrl()) ? + GET_STABLE_ACCESS_TOKEN.replace("https://api.weixin.qq.com", this.getWxMaConfig().getApiHostUrl()) : + GET_STABLE_ACCESS_TOKEN; + WxMaStableAccessTokenRequest wxMaAccessTokenRequest = new WxMaStableAccessTokenRequest(); + wxMaAccessTokenRequest.setAppid(this.getWxMaConfig().getAppid()); + wxMaAccessTokenRequest.setSecret(this.getWxMaConfig().getSecret()); + wxMaAccessTokenRequest.setGrantType("client_credential"); + wxMaAccessTokenRequest.setForceRefresh(forceRefresh); + RequestBody body = RequestBody.Companion.create(wxMaAccessTokenRequest.toJson(), MediaType.parse("application/json; charset=utf-8")); + Request request = new Request.Builder().url(url).post(body).build(); + try (Response response = getRequestHttpClient().newCall(request).execute()) { + return Objects.requireNonNull(response.body()).string(); + } + } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaStableAccessTokenRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaStableAccessTokenRequest.java new file mode 100644 index 0000000000..06a708542a --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaStableAccessTokenRequest.java @@ -0,0 +1,34 @@ +package cn.binarywang.wx.miniapp.bean; + +import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; +import com.google.gson.annotations.SerializedName; +import lombok.Data; + +import java.io.Serializable; + +/** + * 小程序码. + * + * @author Element + * created on 2017/7/27 + */ +@Data +public class WxMaStableAccessTokenRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + @SerializedName("grant_type") + private String grantType = "client_credential"; + + @SerializedName("appid") + private String appid; + @SerializedName("secret") + private String secret; + + @SerializedName("force_refresh") + private boolean forceRefresh; + + public String toJson() { + return WxMaGsonBuilder.create().toJson(this); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java index 208710b75f..084a42cf34 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java @@ -19,6 +19,13 @@ public interface WxMaConfig { */ String getAccessToken(); + //region 稳定版access token + boolean isStableAccessToken(); + + void useStableAccessToken(boolean useStableAccessToken); + //endregion + + /** * Gets access token lock. * diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaDefaultConfigImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaDefaultConfigImpl.java index 074603091c..f1107739f1 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaDefaultConfigImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaDefaultConfigImpl.java @@ -2,6 +2,7 @@ import cn.binarywang.wx.miniapp.config.WxMaConfig; import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; +import lombok.AccessLevel; import lombok.Getter; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; @@ -19,6 +20,13 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { protected volatile String appid; protected volatile String token; + + /** + * 是否使用稳定版获取accessToken接口 + */ + @Getter(value = AccessLevel.NONE) + private boolean useStableAccessToken; + /** * 小程序原始ID */ @@ -81,6 +89,19 @@ public void setAccessToken(String accessToken) { this.accessToken = accessToken; } + //region 使用稳定版接口获取accessToken + @Override + public boolean isStableAccessToken() { + return this.useStableAccessToken; + } + + @Override + public void useStableAccessToken(boolean useStableAccessToken) { + this.useStableAccessToken = useStableAccessToken; + } + //endregion + + @Override public Lock getAccessTokenLock() { return this.accessTokenLock; diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java index dcbe3b3b0b..85cb706b58 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceImplTest.java @@ -33,6 +33,8 @@ public class WxMaServiceImplTest { @Inject private WxMaService wxService; + @Inject + private WxMaServiceOkHttpImpl wxMaServiceOkHttp; public void testRefreshAccessToken() throws WxErrorException { WxMaConfig configStorage = this.wxService.getWxMaConfig(); @@ -44,6 +46,16 @@ public void testRefreshAccessToken() throws WxErrorException { assertTrue(StringUtils.isNotBlank(after)); } + public void testStableRefreshAccessToken() throws WxErrorException { + WxMaConfig configStorage = this.wxMaServiceOkHttp.getWxMaConfig(); + configStorage.useStableAccessToken(true); + String before = configStorage.getAccessToken(); + this.wxMaServiceOkHttp.getAccessToken(false); + String after = configStorage.getAccessToken(); + assertNotEquals(before, after); + assertTrue(StringUtils.isNotBlank(after)); + } + @Test(expectedExceptions = {WxErrorException.class}) public void testGetPaidUnionId() throws WxErrorException { final String unionId = this.wxService.getPaidUnionId("1", null, "3", "4"); @@ -134,7 +146,7 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException { }); try { Object execute = service.execute(re, "http://baidu.com", new HashMap<>()); - Assert.assertTrue(false, "代码应该不会执行到这里"); + Assert.fail("代码应该不会执行到这里"); } catch (WxErrorException e) { Assert.assertEquals(WxMpErrorMsgEnum.CODE_40001.getCode(), e.getError().getErrorCode()); Assert.assertEquals(2, counter.get()); diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/ApiTestModule.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/ApiTestModule.java index a9f5def789..5f3d19c02f 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/ApiTestModule.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/test/ApiTestModule.java @@ -1,17 +1,17 @@ package cn.binarywang.wx.miniapp.test; -import java.io.IOException; -import java.io.InputStream; -import java.util.concurrent.locks.ReentrantLock; - -import me.chanjar.weixin.common.error.WxRuntimeException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.api.impl.WxMaServiceOkHttpImpl; import cn.binarywang.wx.miniapp.config.WxMaConfig; import com.google.inject.Binder; import com.google.inject.Module; +import me.chanjar.weixin.common.error.WxRuntimeException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.locks.ReentrantLock; /** * @author Binary Wang @@ -34,6 +34,11 @@ public void configure(Binder binder) { binder.bind(WxMaService.class).toInstance(wxService); binder.bind(WxMaConfig.class).toInstance(config); + + WxMaServiceOkHttpImpl wxMaServiceOkHttp = new cn.binarywang.wx.miniapp.api.impl.WxMaServiceOkHttpImpl(); + wxMaServiceOkHttp.setWxMaConfig(config); + binder.bind(WxMaServiceOkHttpImpl.class).toInstance(wxMaServiceOkHttp); + } catch (IOException e) { this.log.error(e.getMessage(), e); } diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java index f8dd345ee7..43a351100e 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java @@ -2,7 +2,10 @@ import cn.binarywang.wx.miniapp.config.WxMaConfig; +import lombok.AccessLevel; import lombok.Data; +import lombok.Getter; +import lombok.Setter; import me.chanjar.weixin.common.bean.WxAccessToken; import me.chanjar.weixin.common.enums.TicketType; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; @@ -258,6 +261,12 @@ private static class WxOpenInnerConfigStorage implements WxMpConfigStorage, WxMa private WxMpHostConfig hostConfig; private String apiHostUrl; private String accessTokenUrl; + /** + * 是否使用稳定版获取accessToken接口 + */ + @Getter(value = AccessLevel.NONE) + @Setter(value = AccessLevel.NONE) + private boolean useStableAccessToken; /** * 小程序原始ID @@ -284,6 +293,16 @@ public String getAccessToken() { return wxOpenConfigStorage.getAuthorizerAccessToken(appId); } + @Override + public boolean isStableAccessToken() { + return this.useStableAccessToken; + } + + @Override + public void useStableAccessToken(boolean useStableAccessToken) { + this.useStableAccessToken = useStableAccessToken; + } + @Override public Lock getAccessTokenLock() { return this.accessTokenLock;