Browse Source

:new: #3084【公众号】增加获取稳定版接口调用凭据的接口

Sky 1 year ago
parent
commit
c5e9f17607

+ 50 - 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java

@@ -40,6 +40,7 @@ import org.apache.commons.lang3.StringUtils;
 
 import java.io.IOException;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Lock;
 
 import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.*;
@@ -252,6 +253,55 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH
   }
 
   @Override
+  public String getAccessToken(boolean forceRefresh) throws WxErrorException {
+    if (!forceRefresh && !this.getWxMpConfigStorage().isAccessTokenExpired()) {
+      return this.getWxMpConfigStorage().getAccessToken();
+    }
+
+    Lock lock = this.getWxMpConfigStorage().getAccessTokenLock();
+    boolean locked = false;
+    try {
+      do {
+        locked = lock.tryLock(100, TimeUnit.MILLISECONDS);
+        if (!forceRefresh && !this.getWxMpConfigStorage().isAccessTokenExpired()) {
+          return this.getWxMpConfigStorage().getAccessToken();
+        }
+      } while (!locked);
+
+      String response;
+      if (getWxMpConfigStorage().isStableAccessToken()) {
+        response = doGetStableAccessTokenRequest(forceRefresh);
+      } else {
+        response = doGetAccessTokenRequest();
+      }
+      return extractAccessToken(response);
+    } catch (IOException | InterruptedException e) {
+      throw new WxRuntimeException(e);
+    } finally {
+      if (locked) {
+        lock.unlock();
+      }
+    }
+  }
+
+  /**
+   * 通过网络请求获取AccessToken
+   *
+   * @return .
+   * @throws IOException .
+   */
+  protected abstract String doGetAccessTokenRequest() throws IOException;
+
+
+  /**
+   * 通过网络请求获取稳定版接口调用凭据
+   *
+   * @return .
+   * @throws IOException .
+   */
+  protected abstract String doGetStableAccessTokenRequest(boolean forceRefresh) throws IOException;
+
+  @Override
   public String shortUrl(String longUrl) throws WxErrorException {
     if (longUrl.contains("&access_token=")) {
       throw new WxErrorException("要转换的网址中存在非法字符{&access_token=}," +

+ 56 - 35
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java

@@ -1,23 +1,24 @@
 package me.chanjar.weixin.mp.api.impl;
 
-import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.http.HttpType;
 import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
 import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
+import me.chanjar.weixin.mp.bean.WxMpStableAccessTokenRequest;
 import me.chanjar.weixin.mp.config.WxMpConfigStorage;
 import org.apache.http.HttpHost;
 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;
 
 import java.io.IOException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Lock;
 
 import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.GET_ACCESS_TOKEN_URL;
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.GET_STABLE_ACCESS_TOKEN_URL;
 
 /**
  * apache http client方式实现.
@@ -64,42 +65,62 @@ public class WxMpServiceHttpClientImpl extends BaseWxMpServiceImpl<CloseableHttp
   }
 
   @Override
-  public String getAccessToken(boolean forceRefresh) throws WxErrorException {
-    final WxMpConfigStorage config = this.getWxMpConfigStorage();
-    if (!config.isAccessTokenExpired() && !forceRefresh) {
-      return config.getAccessToken();
-    }
+  protected String doGetAccessTokenRequest() throws IOException {
+    String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(getWxMpConfigStorage()), getWxMpConfigStorage().getAppId(), getWxMpConfigStorage().getSecret());
 
-    Lock lock = config.getAccessTokenLock();
-    boolean locked = false;
+    HttpGet httpGet = null;
+    CloseableHttpResponse response = null;
     try {
-      do {
-        locked = lock.tryLock(100, TimeUnit.MILLISECONDS);
-        if (!forceRefresh && !config.isAccessTokenExpired()) {
-          return config.getAccessToken();
-        }
-      } while (!locked);
-
-      String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(config), config.getAppId(), config.getSecret());
-      try {
-        HttpGet httpGet = new HttpGet(url);
-        if (this.getRequestHttpProxy() != null) {
-          RequestConfig requestConfig = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
-          httpGet.setConfig(requestConfig);
-        }
-        try (CloseableHttpResponse response = getRequestHttpClient().execute(httpGet)) {
-          return this.extractAccessToken(new BasicResponseHandler().handleResponse(response));
-        } finally {
-          httpGet.releaseConnection();
+      httpGet = new HttpGet(url);
+      if (this.getRequestHttpProxy() != null) {
+        RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
+        httpGet.setConfig(config);
+      }
+      response = getRequestHttpClient().execute(httpGet);
+      return new BasicResponseHandler().handleResponse(response);
+    } finally {
+      if (httpGet != null) {
+        httpGet.releaseConnection();
+      }
+      if (response != null) {
+        try {
+          response.close();
+        } catch (IOException e) {
         }
-      } catch (IOException e) {
-        throw new WxRuntimeException(e);
       }
-    } catch (InterruptedException e) {
-      throw new WxRuntimeException(e);
+    }
+  }
+
+  @Override
+  protected String doGetStableAccessTokenRequest(boolean forceRefresh) throws IOException {
+    String url = GET_STABLE_ACCESS_TOKEN_URL.getUrl(getWxMpConfigStorage());
+
+    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);
+      }
+      WxMpStableAccessTokenRequest wxMaAccessTokenRequest = new WxMpStableAccessTokenRequest();
+      wxMaAccessTokenRequest.setAppid(this.getWxMpConfigStorage().getAppId());
+      wxMaAccessTokenRequest.setSecret(this.getWxMpConfigStorage().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 (locked) {
-        lock.unlock();
+      if (httpPost != null) {
+        httpPost.releaseConnection();
+      }
+      if (response != null) {
+        try {
+          response.close();
+        } catch (IOException e) {
+        }
       }
     }
   }

+ 35 - 34
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java

@@ -4,15 +4,16 @@ import jodd.http.HttpConnectionProvider;
 import jodd.http.HttpRequest;
 import jodd.http.ProxyInfo;
 import jodd.http.net.SocketHttpConnectionProvider;
-import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.common.error.WxRuntimeException;
+import jodd.net.MimeTypes;
 import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.mp.bean.WxMpStableAccessTokenRequest;
 import me.chanjar.weixin.mp.config.WxMpConfigStorage;
 
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Lock;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 
 import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.GET_ACCESS_TOKEN_URL;
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.GET_STABLE_ACCESS_TOKEN_URL;
 
 /**
  * jodd-http方式实现.
@@ -51,39 +52,39 @@ public class WxMpServiceJoddHttpImpl extends BaseWxMpServiceImpl<HttpConnectionP
   }
 
   @Override
-  public String getAccessToken(boolean forceRefresh) throws WxErrorException {
-    final WxMpConfigStorage config = this.getWxMpConfigStorage();
-    if (!config.isAccessTokenExpired() && !forceRefresh) {
-      return config.getAccessToken();
+  protected String doGetAccessTokenRequest() throws IOException {
+    String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(getWxMpConfigStorage()), getWxMpConfigStorage().getAppId(), getWxMpConfigStorage().getSecret());
+
+    HttpRequest request = HttpRequest.get(url);
+    if (this.getRequestHttpProxy() != null) {
+      SocketHttpConnectionProvider provider = new SocketHttpConnectionProvider();
+      provider.useProxy(getRequestHttpProxy());
+
+      request.withConnectionProvider(provider);
     }
+    return request.send().bodyText();
+  }
 
-    Lock lock = config.getAccessTokenLock();
-    boolean locked = false;
-    try {
-      do {
-        locked = lock.tryLock(100, TimeUnit.MILLISECONDS);
-        if (!forceRefresh && !config.isAccessTokenExpired()) {
-          return config.getAccessToken();
-        }
-      } while (!locked);
-      String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(config), config.getAppId(), config.getSecret());
-
-      HttpRequest request = HttpRequest.get(url);
-      if (this.getRequestHttpProxy() != null) {
-        SocketHttpConnectionProvider provider = new SocketHttpConnectionProvider();
-        provider.useProxy(getRequestHttpProxy());
-
-        request.withConnectionProvider(provider);
-      }
-
-      return this.extractAccessToken(request.send().bodyText());
-    } catch (InterruptedException e) {
-      throw new WxRuntimeException(e);
-    } finally {
-      if (locked) {
-        lock.unlock();
-      }
+  @Override
+  protected String doGetStableAccessTokenRequest(boolean forceRefresh) throws IOException {
+    String url = GET_STABLE_ACCESS_TOKEN_URL.getUrl(getWxMpConfigStorage());
+
+    WxMpStableAccessTokenRequest wxMaAccessTokenRequest = new WxMpStableAccessTokenRequest();
+    wxMaAccessTokenRequest.setAppid(this.getWxMpConfigStorage().getAppId());
+    wxMaAccessTokenRequest.setSecret(this.getWxMpConfigStorage().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();
   }
 
 }

+ 28 - 36
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java

@@ -1,19 +1,17 @@
 package me.chanjar.weixin.mp.api.impl;
 
-import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.http.HttpType;
 import me.chanjar.weixin.common.util.http.okhttp.DefaultOkHttpClientBuilder;
 import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import me.chanjar.weixin.mp.bean.WxMpStableAccessTokenRequest;
 import me.chanjar.weixin.mp.config.WxMpConfigStorage;
 import okhttp3.*;
 
 import java.io.IOException;
 import java.util.Objects;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Lock;
 
 import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.GET_ACCESS_TOKEN_URL;
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.GET_STABLE_ACCESS_TOKEN_URL;
 
 /**
  * okhttp实现.
@@ -40,38 +38,6 @@ public class WxMpServiceOkHttpImpl extends BaseWxMpServiceImpl<OkHttpClient, OkH
   }
 
   @Override
-  public String getAccessToken(boolean forceRefresh) throws WxErrorException {
-    final WxMpConfigStorage config = this.getWxMpConfigStorage();
-    if (!config.isAccessTokenExpired() && !forceRefresh) {
-      return config.getAccessToken();
-    }
-
-    Lock lock = config.getAccessTokenLock();
-    boolean locked = false;
-    try {
-      do {
-        locked = lock.tryLock(100, TimeUnit.MILLISECONDS);
-        if (!forceRefresh && !config.isAccessTokenExpired()) {
-          return config.getAccessToken();
-        }
-      } while (!locked);
-      String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(config), config.getAppId(), config.getSecret());
-
-      Request request = new Request.Builder().url(url).get().build();
-      Response response = getRequestHttpClient().newCall(request).execute();
-      return this.extractAccessToken(Objects.requireNonNull(response.body()).string());
-    } catch (IOException e) {
-      throw new WxRuntimeException(e);
-    } catch (InterruptedException e) {
-      throw new WxRuntimeException(e);
-    } finally {
-      if (locked) {
-        lock.unlock();
-      }
-    }
-  }
-
-  @Override
   public void initHttp() {
     WxMpConfigStorage wxMpConfigStorage = getWxMpConfigStorage();
     //设置代理
@@ -99,4 +65,30 @@ public class WxMpServiceOkHttpImpl extends BaseWxMpServiceImpl<OkHttpClient, OkH
     }
   }
 
+  @Override
+  protected String doGetAccessTokenRequest() throws IOException {
+    String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(getWxMpConfigStorage()), getWxMpConfigStorage().getAppId(), getWxMpConfigStorage().getSecret());
+
+    Request request = new Request.Builder().url(url).get().build();
+    try (Response response = getRequestHttpClient().newCall(request).execute()) {
+      return Objects.requireNonNull(response.body()).string();
+    }
+  }
+
+  @Override
+  protected String doGetStableAccessTokenRequest(boolean forceRefresh) throws IOException {
+    String url = GET_STABLE_ACCESS_TOKEN_URL.getUrl(getWxMpConfigStorage());
+
+    WxMpStableAccessTokenRequest wxMaAccessTokenRequest = new WxMpStableAccessTokenRequest();
+    wxMaAccessTokenRequest.setAppid(this.getWxMpConfigStorage().getAppId());
+    wxMaAccessTokenRequest.setSecret(this.getWxMpConfigStorage().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();
+    }
+  }
 }

+ 32 - 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpStableAccessTokenRequest.java

@@ -0,0 +1,32 @@
+package me.chanjar.weixin.mp.bean;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
+
+import java.io.Serializable;
+
+/**
+ * @author SKYhuangjing
+ * 微信公众号 获取稳定版接口调用凭据 请求参数
+ */
+@Data
+public class WxMpStableAccessTokenRequest 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 WxMpGsonBuilder.create().toJson(this);
+  }
+}

+ 13 - 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/WxMpConfigStorage.java

@@ -21,6 +21,19 @@ public interface WxMpConfigStorage {
   String getAccessToken();
 
   /**
+   * Is use stable access token api
+   * @Link https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/getStableAccessToken.html
+   * @return the boolean
+   */
+  boolean isStableAccessToken();
+
+  /**
+   * Set use stable access token api
+   * @param useStableAccessToken true is use, false is not
+   */
+  void useStableAccessToken(boolean useStableAccessToken);
+
+  /**
    * Gets access token lock.
    *
    * @return the access token lock

+ 14 - 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/impl/WxMpDefaultConfigImpl.java

@@ -24,6 +24,10 @@ public class WxMpDefaultConfigImpl implements WxMpConfigStorage, Serializable {
 
   protected volatile String appId;
   protected volatile String secret;
+  /**
+   * 是否使用稳定版 Access Token
+   */
+  private boolean useStableAccessToken;
   protected volatile String token;
   protected volatile String templateId;
   protected volatile String accessToken;
@@ -61,6 +65,16 @@ public class WxMpDefaultConfigImpl implements WxMpConfigStorage, Serializable {
   private WxMpHostConfig hostConfig = null;
 
   @Override
+  public boolean isStableAccessToken() {
+    return this.useStableAccessToken;
+  }
+
+  @Override
+  public void useStableAccessToken(boolean useStableAccessToken) {
+    this.useStableAccessToken = useStableAccessToken;
+  }
+
+  @Override
   public boolean isAccessTokenExpired() {
     return System.currentTimeMillis() > this.expiresTime;
   }

+ 4 - 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java

@@ -130,6 +130,10 @@ public interface WxMpApiUrl {
      */
     GET_ACCESS_TOKEN_URL(API_DEFAULT_HOST_URL, "/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"),
     /**
+     * 获取稳定版 access_token.
+     */
+    GET_STABLE_ACCESS_TOKEN_URL(API_DEFAULT_HOST_URL, "/cgi-bin/stable_token"),
+    /**
      * 获得各种类型的ticket.
      */
     GET_TICKET_URL(API_DEFAULT_HOST_URL, "/cgi-bin/ticket/getticket?type="),

+ 10 - 0
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImplTest.java

@@ -212,6 +212,16 @@ public class BaseWxMpServiceImplTest {
       }
 
       @Override
+      protected String doGetAccessTokenRequest() throws IOException {
+        return null;
+      }
+
+      @Override
+      protected String doGetStableAccessTokenRequest(boolean forceRefresh) throws IOException {
+        return null;
+      }
+
+      @Override
       public void initHttp() {
 
       }

+ 11 - 0
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImplTest.java

@@ -59,4 +59,15 @@ public class WxMpServiceImplTest {
     Assert.assertNotEquals(before, after);
     Assert.assertTrue(StringUtils.isNotBlank(after));
   }
+
+  public void testStableRefreshAccessToken() throws WxErrorException {
+    WxMpConfigStorage configStorage = this.wxService.getWxMpConfigStorage();
+    configStorage.useStableAccessToken(true);
+    String before = configStorage.getAccessToken();
+    this.wxService.getAccessToken(false);
+
+    String after = configStorage.getAccessToken();
+    Assert.assertNotEquals(before, after);
+    Assert.assertTrue(StringUtils.isNotBlank(after));
+  }
 }