浏览代码

#844 整合优化ticket管理相关接口代码,方便获取sdk_ticket、jsapi_ticket和card_api_ticket等。

Binary Wang 6 年之前
父节点
当前提交
49633cd123

+ 19 - 35
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpConfigStorage.java

@@ -1,13 +1,14 @@
 package me.chanjar.weixin.mp.api;
 
-import me.chanjar.weixin.common.bean.WxAccessToken;
-import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
-
 import java.io.File;
 import java.util.concurrent.locks.Lock;
 
+import me.chanjar.weixin.common.bean.WxAccessToken;
+import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
+import me.chanjar.weixin.mp.enums.TicketType;
+
 /**
- * 微信客户端配置存储
+ * 微信客户端配置存储.
  *
  * @author chanjarster
  */
@@ -20,62 +21,45 @@ public interface WxMpConfigStorage {
   boolean isAccessTokenExpired();
 
   /**
-   * 强制将access token过期掉
+   * 强制将access token过期掉.
    */
   void expireAccessToken();
 
   /**
-   * 应该是线程安全的
+   * 应该是线程安全的.
    *
    * @param accessToken 要更新的WxAccessToken对象
    */
   void updateAccessToken(WxAccessToken accessToken);
 
   /**
-   * 应该是线程安全的
+   * 应该是线程安全的.
    *
    * @param accessToken      新的accessToken值
    * @param expiresInSeconds 过期时间,以秒为单位
    */
   void updateAccessToken(String accessToken, int expiresInSeconds);
 
-  String getJsapiTicket();
-
-  Lock getJsapiTicketLock();
-
-  boolean isJsapiTicketExpired();
-
-  /**
-   * 强制将jsapi ticket过期掉
-   */
-  void expireJsapiTicket();
-
-  /**
-   * 应该是线程安全的
-   *
-   * @param jsapiTicket      新的jsapi ticket值
-   * @param expiresInSeconds 过期时间,以秒为单位
-   */
-  void updateJsapiTicket(String jsapiTicket, int expiresInSeconds);
-
-  String getCardApiTicket();
+  String getTicket(TicketType type);
 
-  Lock getCardApiTicketLock();
+  Lock getTicketLock(TicketType type);
 
-  boolean isCardApiTicketExpired();
+  boolean isTicketExpired(TicketType type);
 
   /**
-   * 强制将卡券api ticket过期掉
+   * 强制将ticket过期掉.
    */
-  void expireCardApiTicket();
+  void expireTicket(TicketType type);
 
   /**
+   * 更新ticket.
    * 应该是线程安全的
    *
-   * @param cardApiTicket    新的cardApi ticket值
+   * @param type             ticket类型
+   * @param ticket           新的ticket值
    * @param expiresInSeconds 过期时间,以秒为单位
    */
-  void updateCardApiTicket(String cardApiTicket, int expiresInSeconds);
+  void updateTicket(TicketType type, String ticket, int expiresInSeconds);
 
   String getAppId();
 
@@ -102,14 +86,14 @@ public interface WxMpConfigStorage {
   File getTmpDirFile();
 
   /**
-   * http client builder
+   * http client builder.
    *
    * @return ApacheHttpClientBuilder
    */
   ApacheHttpClientBuilder getApacheHttpClientBuilder();
 
   /**
-   * 是否自动刷新token
+   * 是否自动刷新token.
    */
   boolean autoRefreshToken();
 

+ 103 - 214
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInMemoryConfigStorage.java

@@ -1,19 +1,24 @@
 package me.chanjar.weixin.mp.api;
 
 import java.io.File;
+import java.io.Serializable;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
+import lombok.Data;
 import me.chanjar.weixin.common.bean.WxAccessToken;
 import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
+import me.chanjar.weixin.mp.enums.TicketType;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
 /**
- * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化
+ * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化.
  *
  * @author chanjarster
  */
-public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
+@Data
+public class WxMpInMemoryConfigStorage implements WxMpConfigStorage, Serializable {
+  private static final long serialVersionUID = -6646519023303395185L;
 
   protected volatile String appId;
   protected volatile String secret;
@@ -33,35 +38,22 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
   protected volatile String jsapiTicket;
   protected volatile long jsapiTicketExpiresTime;
 
+  protected volatile String sdkTicket;
+  protected volatile long sdkTicketExpiresTime;
+
   protected volatile String cardApiTicket;
   protected volatile long cardApiTicketExpiresTime;
 
   protected Lock accessTokenLock = new ReentrantLock();
   protected Lock jsapiTicketLock = new ReentrantLock();
+  protected Lock sdkTicketLock = new ReentrantLock();
   protected Lock cardApiTicketLock = new ReentrantLock();
 
-  /**
-   * 临时文件目录
-   */
   protected volatile File tmpDirFile;
 
   protected volatile ApacheHttpClientBuilder apacheHttpClientBuilder;
 
   @Override
-  public String getAccessToken() {
-    return this.accessToken;
-  }
-
-  public void setAccessToken(String accessToken) {
-    this.accessToken = accessToken;
-  }
-
-  @Override
-  public Lock getAccessTokenLock() {
-    return this.accessTokenLock;
-  }
-
-  @Override
   public boolean isAccessTokenExpired() {
     return System.currentTimeMillis() > this.expiresTime;
   }
@@ -83,167 +75,98 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
   }
 
   @Override
-  public String getJsapiTicket() {
-    return this.jsapiTicket;
-  }
-
-  public void setJsapiTicket(String jsapiTicket) {
-    this.jsapiTicket = jsapiTicket;
-  }
-
-  @Override
-  public Lock getJsapiTicketLock() {
-    return this.jsapiTicketLock;
-  }
-
-  @Override
-  public boolean isJsapiTicketExpired() {
-    return System.currentTimeMillis() > this.jsapiTicketExpiresTime;
-  }
-
-  @Override
-  public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) {
-    this.jsapiTicket = jsapiTicket;
-    // 预留200秒的时间
-    this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
-  }
-
-  @Override
-  public void expireJsapiTicket() {
-    this.jsapiTicketExpiresTime = 0;
-  }
-
-  /**
-   * 卡券api_ticket
-   */
-  @Override
-  public String getCardApiTicket() {
-    return this.cardApiTicket;
-  }
-
-  public void setCardApiTicket(String cardApiTicket) {
-    this.cardApiTicket = cardApiTicket;
-  }
-
-  @Override
-  public Lock getCardApiTicketLock() {
-    return this.cardApiTicketLock;
-  }
-
-  @Override
-  public boolean isCardApiTicketExpired() {
-    return System.currentTimeMillis() > this.cardApiTicketExpiresTime;
-  }
-
-  @Override
-  public synchronized void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) {
-    this.cardApiTicket = cardApiTicket;
-    // 预留200秒的时间
-    this.cardApiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
-  }
-
-  @Override
-  public void expireCardApiTicket() {
-    this.cardApiTicketExpiresTime = 0;
-  }
-
-  @Override
-  public String getAppId() {
-    return this.appId;
-  }
-
-  public void setAppId(String appId) {
-    this.appId = appId;
-  }
-
-  @Override
-  public String getSecret() {
-    return this.secret;
-  }
-
-  public void setSecret(String secret) {
-    this.secret = secret;
-  }
-
-  @Override
-  public String getToken() {
-    return this.token;
-  }
-
-  public void setToken(String token) {
-    this.token = token;
-  }
-
-  @Override
-  public String getTemplateId() {
-    return this.templateId;
-  }
-
-  public void setTemplateId(String templateId) {
-    this.templateId = templateId;
-  }
-
-  @Override
-  public long getExpiresTime() {
-    return this.expiresTime;
-  }
-
-  public void setExpiresTime(long expiresTime) {
-    this.expiresTime = expiresTime;
-  }
-
-  @Override
-  public String getAesKey() {
-    return this.aesKey;
-  }
-
-  public void setAesKey(String aesKey) {
-    this.aesKey = aesKey;
-  }
-
-  @Override
-  public String getOauth2redirectUri() {
-    return this.oauth2redirectUri;
-  }
-
-  public void setOauth2redirectUri(String oauth2redirectUri) {
-    this.oauth2redirectUri = oauth2redirectUri;
-  }
-
-  @Override
-  public String getHttpProxyHost() {
-    return this.httpProxyHost;
-  }
-
-  public void setHttpProxyHost(String httpProxyHost) {
-    this.httpProxyHost = httpProxyHost;
-  }
-
-  @Override
-  public int getHttpProxyPort() {
-    return this.httpProxyPort;
-  }
-
-  public void setHttpProxyPort(int httpProxyPort) {
-    this.httpProxyPort = httpProxyPort;
-  }
-
-  @Override
-  public String getHttpProxyUsername() {
-    return this.httpProxyUsername;
-  }
-
-  public void setHttpProxyUsername(String httpProxyUsername) {
-    this.httpProxyUsername = httpProxyUsername;
-  }
-
-  @Override
-  public String getHttpProxyPassword() {
-    return this.httpProxyPassword;
-  }
-
-  public void setHttpProxyPassword(String httpProxyPassword) {
-    this.httpProxyPassword = httpProxyPassword;
+  public String getTicket(TicketType type) {
+    switch (type) {
+      case SDK:
+        return this.sdkTicket;
+      case JSAPI:
+        return this.jsapiTicket;
+      case WX_CARD:
+        return this.cardApiTicket;
+      default:
+        return null;
+    }
+  }
+
+  public void setTicket(TicketType type, String ticket) {
+    switch (type) {
+      case JSAPI:
+        this.jsapiTicket = ticket;
+        break;
+      case WX_CARD:
+        this.cardApiTicket = ticket;
+        break;
+      case SDK:
+        this.sdkTicket = ticket;
+        break;
+      default:
+    }
+  }
+
+  @Override
+  public Lock getTicketLock(TicketType type) {
+    switch (type) {
+      case SDK:
+        return this.sdkTicketLock;
+      case JSAPI:
+        return this.jsapiTicketLock;
+      case WX_CARD:
+        return this.cardApiTicketLock;
+      default:
+        return null;
+    }
+  }
+
+  @Override
+  public boolean isTicketExpired(TicketType type) {
+    switch (type) {
+      case SDK:
+        return System.currentTimeMillis() > this.sdkTicketExpiresTime;
+      case JSAPI:
+        return System.currentTimeMillis() > this.jsapiTicketExpiresTime;
+      case WX_CARD:
+        return System.currentTimeMillis() > this.cardApiTicketExpiresTime;
+      default:
+        return false;
+    }
+  }
+
+  @Override
+  public synchronized void updateTicket(TicketType type, String ticket, int expiresInSeconds) {
+    switch (type) {
+      case JSAPI:
+        this.jsapiTicket = ticket;
+        // 预留200秒的时间
+        this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
+        break;
+      case WX_CARD:
+        this.cardApiTicket = ticket;
+        // 预留200秒的时间
+        this.cardApiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
+        break;
+      case SDK:
+        this.sdkTicket = ticket;
+        // 预留200秒的时间
+        this.sdkTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
+        break;
+      default:
+    }
+  }
+
+  @Override
+  public void expireTicket(TicketType type) {
+    switch (type) {
+      case JSAPI:
+        this.jsapiTicketExpiresTime = 0;
+        break;
+      case WX_CARD:
+        this.cardApiTicketExpiresTime = 0;
+        break;
+      case SDK:
+        this.sdkTicketExpiresTime = 0;
+        break;
+      default:
+    }
   }
 
   @Override
@@ -252,40 +175,6 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
   }
 
   @Override
-  public File getTmpDirFile() {
-    return this.tmpDirFile;
-  }
-
-  public void setTmpDirFile(File tmpDirFile) {
-    this.tmpDirFile = tmpDirFile;
-  }
-
-  @Override
-  public ApacheHttpClientBuilder getApacheHttpClientBuilder() {
-    return this.apacheHttpClientBuilder;
-  }
-
-  public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) {
-    this.apacheHttpClientBuilder = apacheHttpClientBuilder;
-  }
-
-  public long getJsapiTicketExpiresTime() {
-    return this.jsapiTicketExpiresTime;
-  }
-
-  public void setJsapiTicketExpiresTime(long jsapiTicketExpiresTime) {
-    this.jsapiTicketExpiresTime = jsapiTicketExpiresTime;
-  }
-
-  public long getCardApiTicketExpiresTime() {
-    return this.cardApiTicketExpiresTime;
-  }
-
-  public void setCardApiTicketExpiresTime(long cardApiTicketExpiresTime) {
-    this.cardApiTicketExpiresTime = cardApiTicketExpiresTime;
-  }
-
-  @Override
   public boolean autoRefreshToken() {
     return true;
   }

+ 19 - 52
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpInRedisConfigStorage.java

@@ -1,51 +1,45 @@
 package me.chanjar.weixin.mp.api;
 
+import me.chanjar.weixin.mp.enums.TicketType;
 import redis.clients.jedis.Jedis;
 import redis.clients.jedis.JedisPool;
 
 /**
- * 基于Redis的微信配置provider
+ * 基于Redis的微信配置provider.
+ *
  * <pre>
  *    使用说明:本实现仅供参考,并不完整,
  *    比如为减少项目依赖,未加入redis分布式锁的实现,如有需要请自行实现。
  * </pre>
+ *
  * @author nickwong
  */
 @SuppressWarnings("hiding")
 public class WxMpInRedisConfigStorage extends WxMpInMemoryConfigStorage {
-
-  private final static String ACCESS_TOKEN_KEY = "wechat_access_token_";
-
-  private final static String JSAPI_TICKET_KEY = "wechat_jsapi_ticket_";
-
-  private final static String CARDAPI_TICKET_KEY = "wechat_cardapi_ticket_";
+  private static final String ACCESS_TOKEN_KEY = "wx:access_token:";
 
   /**
-   * 使用连接池保证线程安全
+   * 使用连接池保证线程安全.
    */
   protected final JedisPool jedisPool;
 
   private String accessTokenKey;
 
-  private String jsapiTicketKey;
-
-  private String cardapiTicketKey;
-
   public WxMpInRedisConfigStorage(JedisPool jedisPool) {
     this.jedisPool = jedisPool;
   }
 
   /**
-   * 每个公众号生成独有的存储key
-   *
-   * @param appId
+   * 每个公众号生成独有的存储key.
    */
   @Override
   public void setAppId(String appId) {
     super.setAppId(appId);
     this.accessTokenKey = ACCESS_TOKEN_KEY.concat(appId);
-    this.jsapiTicketKey = JSAPI_TICKET_KEY.concat(appId);
-    this.cardapiTicketKey = CARDAPI_TICKET_KEY.concat(appId);
+  }
+
+  private String getTicketRedisKey(TicketType type) {
+    return String.format("wx:ticket:key:%s:%s", this.appId, type.getCode());
   }
 
   @Override
@@ -77,58 +71,31 @@ public class WxMpInRedisConfigStorage extends WxMpInMemoryConfigStorage {
   }
 
   @Override
-  public String getJsapiTicket() {
-    try (Jedis jedis = this.jedisPool.getResource()) {
-      return jedis.get(this.jsapiTicketKey);
-    }
-  }
-
-  @Override
-  public boolean isJsapiTicketExpired() {
-    try (Jedis jedis = this.jedisPool.getResource()) {
-      return jedis.ttl(this.jsapiTicketKey) < 2;
-    }
-  }
-
-  @Override
-  public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) {
+  public String getTicket(TicketType type) {
     try (Jedis jedis = this.jedisPool.getResource()) {
-      jedis.setex(this.jsapiTicketKey, expiresInSeconds - 200, jsapiTicket);
+      return jedis.get(this.getTicketRedisKey(type));
     }
   }
 
   @Override
-  public void expireJsapiTicket() {
+  public boolean isTicketExpired(TicketType type) {
     try (Jedis jedis = this.jedisPool.getResource()) {
-      jedis.expire(this.jsapiTicketKey, 0);
+      return jedis.ttl(this.getTicketRedisKey(type)) < 2;
     }
   }
 
   @Override
-  public String getCardApiTicket() {
+  public synchronized void updateTicket(TicketType type, String jsapiTicket, int expiresInSeconds) {
     try (Jedis jedis = this.jedisPool.getResource()) {
-      return jedis.get(this.cardapiTicketKey);
+      jedis.setex(this.getTicketRedisKey(type), expiresInSeconds - 200, jsapiTicket);
     }
   }
 
   @Override
-  public boolean isCardApiTicketExpired() {
+  public void expireTicket(TicketType type) {
     try (Jedis jedis = this.jedisPool.getResource()) {
-      return jedis.ttl(this.cardapiTicketKey) < 2;
+      jedis.expire(this.getTicketRedisKey(type), 0);
     }
   }
 
-  @Override
-  public synchronized void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) {
-    try (Jedis jedis = this.jedisPool.getResource()) {
-      jedis.setex(this.cardapiTicketKey, expiresInSeconds - 200, cardApiTicket);
-    }
-  }
-
-  @Override
-  public void expireCardApiTicket() {
-    try (Jedis jedis = this.jedisPool.getResource()) {
-      jedis.expire(this.cardapiTicketKey, 0);
-    }
-  }
 }

+ 75 - 55
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java

@@ -10,76 +10,79 @@ import me.chanjar.weixin.mp.bean.result.WxMpCurrentAutoReplyInfo;
 import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
 import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult;
 import me.chanjar.weixin.mp.bean.result.WxMpUser;
+import me.chanjar.weixin.mp.enums.TicketType;
 
 /**
- * 微信API的Service
+ * 微信公众号API的Service.
+ *
+ * @author chanjarster
  */
 public interface WxMpService {
   /**
-   * 获取access_token
+   * 获取access_token.
    */
   String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
   /**
-   * 获得jsapi_ticket
+   * 获得各种类型的ticket.
    */
-  String GET_JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi";
+  String GET_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=";
   /**
-   * 长链接转短链接接口
+   * 长链接转短链接接口.
    */
   String SHORTURL_API_URL = "https://api.weixin.qq.com/cgi-bin/shorturl";
   /**
-   * 语义查询接口
+   * 语义查询接口.
    */
   String SEMANTIC_SEMPROXY_SEARCH_URL = "https://api.weixin.qq.com/semantic/semproxy/search";
   /**
-   * 用code换取oauth2的access token
+   * 用code换取oauth2的access token.
    */
   String OAUTH2_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
   /**
-   * 刷新oauth2的access token
+   * 刷新oauth2的access token.
    */
   String OAUTH2_REFRESH_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s";
   /**
-   * 用oauth2获取用户信息
+   * 用oauth2获取用户信息.
    */
   String OAUTH2_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=%s";
   /**
-   * 验证oauth2的access token是否有效
+   * 验证oauth2的access token是否有效.
    */
   String OAUTH2_VALIDATE_TOKEN_URL = "https://api.weixin.qq.com/sns/auth?access_token=%s&openid=%s";
   /**
-   * 获取微信服务器IP地址
+   * 获取微信服务器IP地址.
    */
   String GET_CALLBACK_IP_URL = "https://api.weixin.qq.com/cgi-bin/getcallbackip";
   /**
-   * 第三方使用网站应用授权登录的url
+   * 第三方使用网站应用授权登录的url.
    */
   String QRCONNECT_URL = "https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect";
   /**
-   * oauth2授权的url连接
+   * oauth2授权的url连接.
    */
   String CONNECT_OAUTH2_AUTHORIZE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s&connect_redirect=1#wechat_redirect";
 
   /**
-   * 获取公众号的自动回复规则
+   * 获取公众号的自动回复规则.
    */
   String GET_CURRENT_AUTOREPLY_INFO_URL = "https://api.weixin.qq.com/cgi-bin/get_current_autoreply_info";
 
   /**
-   * 公众号调用或第三方平台帮公众号调用对公众号的所有api调用(包括第三方帮其调用)次数进行清零
+   * 公众号调用或第三方平台帮公众号调用对公众号的所有api调用(包括第三方帮其调用)次数进行清零.
    */
   String CLEAR_QUOTA_URL = "https://api.weixin.qq.com/cgi-bin/clear_quota";
 
   /**
    * <pre>
-   * 验证消息的确来自微信服务器
+   * 验证消息的确来自微信服务器.
    * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319&token=&lang=zh_CN
    * </pre>
    */
   boolean checkSignature(String timestamp, String nonce, String signature);
 
   /**
-   * 获取access_token, 不强制刷新access_token
+   * 获取access_token, 不强制刷新access_token.
    *
    * @see #getAccessToken(boolean)
    */
@@ -87,7 +90,7 @@ public interface WxMpService {
 
   /**
    * <pre>
-   * 获取access_token,本方法线程安全
+   * 获取access_token,本方法线程安全.
    * 且在多线程同时刷新时只刷新一次,避免超出2000次/日的调用次数上限
    *
    * 另:本service的所有方法都会在access_token过期时调用此方法
@@ -102,7 +105,24 @@ public interface WxMpService {
   String getAccessToken(boolean forceRefresh) throws WxErrorException;
 
   /**
-   * 获得jsapi_ticket,不强制刷新jsapi_ticket
+   * 获得ticket,不强制刷新ticket.
+   *
+   * @see #getTicket(TicketType, boolean)
+   */
+  String getTicket(TicketType type) throws WxErrorException;
+
+  /**
+   * <pre>
+   * 获得ticket.
+   * 获得时会检查 Token是否过期,如果过期了,那么就刷新一下,否则就什么都不干
+   * </pre>
+   *
+   * @param forceRefresh 强制刷新
+   */
+  String getTicket(TicketType type, boolean forceRefresh) throws WxErrorException;
+
+  /**
+   * 获得jsapi_ticket,不强制刷新jsapi_ticket.
    *
    * @see #getJsapiTicket(boolean)
    */
@@ -110,7 +130,7 @@ public interface WxMpService {
 
   /**
    * <pre>
-   * 获得jsapi_ticket
+   * 获得jsapi_ticket.
    * 获得时会检查jsapiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干
    *
    * 详情请见:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN
@@ -122,7 +142,7 @@ public interface WxMpService {
 
   /**
    * <pre>
-   * 创建调用jsapi时所需要的签名
+   * 创建调用jsapi时所需要的签名.
    *
    * 详情请见:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN
    * </pre>
@@ -131,7 +151,7 @@ public interface WxMpService {
 
   /**
    * <pre>
-   * 长链接转短链接接口
+   * 长链接转短链接接口.
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=长链接转短链接接口
    * </pre>
    */
@@ -139,7 +159,7 @@ public interface WxMpService {
 
   /**
    * <pre>
-   * 语义查询接口
+   * 语义查询接口.
    * 详情请见:http://mp.weixin.qq.com/wiki/index.php?title=语义理解
    * </pre>
    */
@@ -147,7 +167,7 @@ public interface WxMpService {
 
   /**
    * <pre>
-   * 构造第三方使用网站应用授权登录的url
+   * 构造第三方使用网站应用授权登录的url.
    * 详情请见: <a href="https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN">网站应用微信登录开发指南</a>
    * URL格式为:https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
    * </pre>
@@ -161,7 +181,7 @@ public interface WxMpService {
 
   /**
    * <pre>
-   * 构造oauth2授权的url连接
+   * 构造oauth2授权的url连接.
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=网页授权获取用户基本信息
    * </pre>
    *
@@ -172,7 +192,7 @@ public interface WxMpService {
 
   /**
    * <pre>
-   * 用code换取oauth2的access token
+   * 用code换取oauth2的access token.
    * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=网页授权获取用户基本信息
    * </pre>
    */
@@ -180,14 +200,14 @@ public interface WxMpService {
 
   /**
    * <pre>
-   * 刷新oauth2的access token
+   * 刷新oauth2的access token.
    * </pre>
    */
   WxMpOAuth2AccessToken oauth2refreshAccessToken(String refreshToken) throws WxErrorException;
 
   /**
    * <pre>
-   * 用oauth2获取用户信息, 当前面引导授权时的scope是snsapi_userinfo的时候才可以
+   * 用oauth2获取用户信息, 当前面引导授权时的scope是snsapi_userinfo的时候才可以.
    * </pre>
    *
    * @param lang zh_CN, zh_TW, en
@@ -196,7 +216,7 @@ public interface WxMpService {
 
   /**
    * <pre>
-   * 验证oauth2的access token是否有效
+   * 验证oauth2的access token是否有效.
    * </pre>
    */
   boolean oauth2validateAccessToken(WxMpOAuth2AccessToken oAuth2AccessToken);
@@ -211,7 +231,7 @@ public interface WxMpService {
 
   /**
    * <pre>
-   * 获取公众号的自动回复规则
+   * 获取公众号的自动回复规则.
    * http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751299&token=&lang=zh_CN
    * 开发者可以通过该接口,获取公众号当前使用的自动回复规则,包括关注后自动回复、消息自动回复(60分钟内触发一次)、关键词自动回复。
    * 请注意:
@@ -240,12 +260,12 @@ public interface WxMpService {
   void clearQuota(String appid) throws WxErrorException;
 
   /**
-   * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求
+   * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求.
    */
   String get(String url, String queryParam) throws WxErrorException;
 
   /**
-   * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求
+   * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的POST请求.
    */
   String post(String url, String postData) throws WxErrorException;
 
@@ -260,7 +280,7 @@ public interface WxMpService {
 
   /**
    * <pre>
-   * 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试
+   * 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试.
    * @param retrySleepMillis 默认:1000ms
    * </pre>
    */
@@ -268,131 +288,131 @@ public interface WxMpService {
 
   /**
    * <pre>
-   * 设置当微信系统响应系统繁忙时,最大重试次数
+   * 设置当微信系统响应系统繁忙时,最大重试次数.
    * 默认:5次
    * </pre>
    */
   void setMaxRetryTimes(int maxRetryTimes);
 
   /**
-   * 获取WxMpConfigStorage 对象
+   * 获取WxMpConfigStorage 对象.
    *
    * @return WxMpConfigStorage
    */
   WxMpConfigStorage getWxMpConfigStorage();
 
   /**
-   * 注入 {@link WxMpConfigStorage} 的实现
+   * 注入 {@link WxMpConfigStorage} 的实现.
    */
   void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider);
 
   /**
-   * 返回客服接口方法实现类,以方便调用其各个接口
+   * 返回客服接口方法实现类,以方便调用其各个接口.
    *
    * @return WxMpKefuService
    */
   WxMpKefuService getKefuService();
 
   /**
-   * 返回素材相关接口方法的实现类对象,以方便调用其各个接口
+   * 返回素材相关接口方法的实现类对象,以方便调用其各个接口.
    *
    * @return WxMpMaterialService
    */
   WxMpMaterialService getMaterialService();
 
   /**
-   * 返回菜单相关接口方法的实现类对象,以方便调用其各个接口
+   * 返回菜单相关接口方法的实现类对象,以方便调用其各个接口.
    *
    * @return WxMpMenuService
    */
   WxMpMenuService getMenuService();
 
   /**
-   * 返回用户相关接口方法的实现类对象,以方便调用其各个接口
+   * 返回用户相关接口方法的实现类对象,以方便调用其各个接口.
    *
    * @return WxMpUserService
    */
   WxMpUserService getUserService();
 
   /**
-   * 返回用户标签相关接口方法的实现类对象,以方便调用其各个接口
+   * 返回用户标签相关接口方法的实现类对象,以方便调用其各个接口.
    *
    * @return WxMpUserTagService
    */
   WxMpUserTagService getUserTagService();
 
   /**
-   * 返回二维码相关接口方法的实现类对象,以方便调用其各个接口
+   * 返回二维码相关接口方法的实现类对象,以方便调用其各个接口.
    *
    * @return WxMpQrcodeService
    */
   WxMpQrcodeService getQrcodeService();
 
   /**
-   * 返回卡券相关接口方法的实现类对象,以方便调用其各个接口
+   * 返回卡券相关接口方法的实现类对象,以方便调用其各个接口.
    *
    * @return WxMpCardService
    */
   WxMpCardService getCardService();
 
   /**
-   * 返回数据分析统计相关接口方法的实现类对象,以方便调用其各个接口
+   * 返回数据分析统计相关接口方法的实现类对象,以方便调用其各个接口.
    *
    * @return WxMpDataCubeService
    */
   WxMpDataCubeService getDataCubeService();
 
   /**
-   * 返回用户黑名单管理相关接口方法的实现类对象,以方便调用其各个接口
+   * 返回用户黑名单管理相关接口方法的实现类对象,以方便调用其各个接口.
    *
    * @return WxMpUserBlacklistService
    */
   WxMpUserBlacklistService getBlackListService();
 
   /**
-   * 返回门店管理相关接口方法的实现类对象,以方便调用其各个接口
+   * 返回门店管理相关接口方法的实现类对象,以方便调用其各个接口.
    *
    * @return WxMpStoreService
    */
   WxMpStoreService getStoreService();
 
   /**
-   * 返回模板消息相关接口方法的实现类对象,以方便调用其各个接口
+   * 返回模板消息相关接口方法的实现类对象,以方便调用其各个接口.
    *
    * @return WxMpTemplateMsgService
    */
   WxMpTemplateMsgService getTemplateMsgService();
 
   /**
-   * 返回一次性订阅消息相关接口方法的实现类对象,以方便调用其各个接口
+   * 返回一次性订阅消息相关接口方法的实现类对象,以方便调用其各个接口.
    *
    * @return WxMpSubscribeMsgService
    */
   WxMpSubscribeMsgService getSubscribeMsgService();
 
   /**
-   * 返回硬件平台相关接口方法的实现类对象,以方便调用其各个接口
+   * 返回硬件平台相关接口方法的实现类对象,以方便调用其各个接口.
    *
    * @return WxMpDeviceService
    */
   WxMpDeviceService getDeviceService();
 
   /**
-   * 返回摇一摇周边相关接口方法的实现类对象,以方便调用其各个接口
+   * 返回摇一摇周边相关接口方法的实现类对象,以方便调用其各个接口.
    *
    * @return WxMpShakeService
    */
   WxMpShakeService getShakeService();
 
   /**
-   * 返回会员卡相关接口方法的实现类对象,以方便调用其各个接口
+   * 返回会员卡相关接口方法的实现类对象,以方便调用其各个接口.
    *
    * @return WxMpMemberCardService
    */
   WxMpMemberCardService getMemberCardService();
 
   /**
-   * 初始化http请求对象
+   * 初始化http请求对象.
    */
   void initHttp();
 
@@ -402,21 +422,21 @@ public interface WxMpService {
   RequestHttp getRequestHttp();
 
   /**
-   * 返回群发消息相关接口方法的实现类对象,以方便调用其各个接口
+   * 返回群发消息相关接口方法的实现类对象,以方便调用其各个接口.
    *
    * @return WxMpMassMessageService
    */
   WxMpMassMessageService getMassMessageService();
 
   /**
-   * 返回AI开放接口方法的实现类对象,以方便调用其各个接口
+   * 返回AI开放接口方法的实现类对象,以方便调用其各个接口.
    *
    * @return WxMpAiOpenService
    */
   WxMpAiOpenService getAiOpenService();
 
   /**
-   * 返回WIFI接口方法的实现类对象,以方便调用其各个接口
+   * 返回WIFI接口方法的实现类对象,以方便调用其各个接口.
    *
    * @return WxMpWifiService
    */

+ 55 - 19
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java

@@ -1,5 +1,12 @@
 package me.chanjar.weixin.mp.api.impl;
 
+import java.io.IOException;
+import java.util.concurrent.locks.Lock;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import com.google.gson.JsonArray;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
@@ -12,19 +19,37 @@ import me.chanjar.weixin.common.session.WxSessionManager;
 import me.chanjar.weixin.common.util.DataUtils;
 import me.chanjar.weixin.common.util.RandomUtils;
 import me.chanjar.weixin.common.util.crypto.SHA1;
-import me.chanjar.weixin.common.util.http.*;
-import me.chanjar.weixin.mp.api.*;
+import me.chanjar.weixin.common.util.http.RequestExecutor;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
+import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
+import me.chanjar.weixin.common.util.http.URIUtil;
+import me.chanjar.weixin.mp.api.WxMpAiOpenService;
+import me.chanjar.weixin.mp.api.WxMpCardService;
+import me.chanjar.weixin.mp.api.WxMpConfigStorage;
+import me.chanjar.weixin.mp.api.WxMpDataCubeService;
+import me.chanjar.weixin.mp.api.WxMpDeviceService;
+import me.chanjar.weixin.mp.api.WxMpKefuService;
+import me.chanjar.weixin.mp.api.WxMpMassMessageService;
+import me.chanjar.weixin.mp.api.WxMpMaterialService;
+import me.chanjar.weixin.mp.api.WxMpMemberCardService;
+import me.chanjar.weixin.mp.api.WxMpMenuService;
+import me.chanjar.weixin.mp.api.WxMpQrcodeService;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.api.WxMpShakeService;
+import me.chanjar.weixin.mp.api.WxMpStoreService;
+import me.chanjar.weixin.mp.api.WxMpSubscribeMsgService;
+import me.chanjar.weixin.mp.api.WxMpTemplateMsgService;
+import me.chanjar.weixin.mp.api.WxMpUserBlacklistService;
+import me.chanjar.weixin.mp.api.WxMpUserService;
+import me.chanjar.weixin.mp.api.WxMpUserTagService;
+import me.chanjar.weixin.mp.api.WxMpWifiService;
 import me.chanjar.weixin.mp.bean.WxMpSemanticQuery;
 import me.chanjar.weixin.mp.bean.result.WxMpCurrentAutoReplyInfo;
 import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
 import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult;
 import me.chanjar.weixin.mp.bean.result.WxMpUser;
-import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.util.concurrent.locks.Lock;
+import me.chanjar.weixin.mp.enums.TicketType;
 
 /**
  * @author someone
@@ -71,31 +96,42 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH
   }
 
   @Override
-  public String getJsapiTicket() throws WxErrorException {
-    return getJsapiTicket(false);
+  public String getTicket(TicketType type) throws WxErrorException {
+    return this.getTicket(type, false);
   }
 
   @Override
-  public String getJsapiTicket(boolean forceRefresh) throws WxErrorException {
-    Lock lock = this.getWxMpConfigStorage().getJsapiTicketLock();
+  public String getTicket(TicketType type, boolean forceRefresh) throws WxErrorException {
+    Lock lock = this.getWxMpConfigStorage().getTicketLock(type);
     try {
       lock.lock();
       if (forceRefresh) {
-        this.getWxMpConfigStorage().expireJsapiTicket();
+        this.getWxMpConfigStorage().expireTicket(type);
       }
 
-      if (this.getWxMpConfigStorage().isJsapiTicketExpired()) {
-        String responseContent = execute(SimpleGetRequestExecutor.create(this), WxMpService.GET_JSAPI_TICKET_URL, null);
-        JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent);
-        JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
+      if (this.getWxMpConfigStorage().isTicketExpired(type)) {
+        String responseContent = execute(SimpleGetRequestExecutor.create(this),
+          WxMpService.GET_TICKET_URL + type.getCode(), null);
+        JsonObject tmpJsonObject = JSON_PARSER.parse(responseContent).getAsJsonObject();
         String jsapiTicket = tmpJsonObject.get("ticket").getAsString();
         int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
-        this.getWxMpConfigStorage().updateJsapiTicket(jsapiTicket, expiresInSeconds);
+        this.getWxMpConfigStorage().updateTicket(type, jsapiTicket, expiresInSeconds);
       }
     } finally {
       lock.unlock();
     }
-    return this.getWxMpConfigStorage().getJsapiTicket();
+
+    return this.getWxMpConfigStorage().getTicket(type);
+  }
+
+  @Override
+  public String getJsapiTicket() throws WxErrorException {
+    return this.getJsapiTicket(false);
+  }
+
+  @Override
+  public String getJsapiTicket(boolean forceRefresh) throws WxErrorException {
+    return this.getTicket(TicketType.JSAPI, forceRefresh);
   }
 
   @Override

+ 26 - 33
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java

@@ -26,13 +26,15 @@ import me.chanjar.weixin.mp.bean.card.WxMpCardLandingPageCreateRequest;
 import me.chanjar.weixin.mp.bean.card.WxMpCardLandingPageCreateResult;
 import me.chanjar.weixin.mp.bean.card.WxMpCardQrcodeCreateResult;
 import me.chanjar.weixin.mp.bean.result.WxMpCardResult;
+import me.chanjar.weixin.mp.enums.TicketType;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
 /**
  * Created by Binary Wang on 2016/7/27.
+ *
+ * @author BinaryWang
  */
 public class WxMpCardServiceImpl implements WxMpCardService {
-
   private final Logger log = LoggerFactory.getLogger(WxMpCardServiceImpl.class);
 
   private WxMpService wxMpService;
@@ -49,7 +51,7 @@ public class WxMpCardServiceImpl implements WxMpCardService {
   }
 
   /**
-   * 获得卡券api_ticket,不强制刷新卡券api_ticket
+   * 获得卡券api_ticket,不强制刷新卡券api_ticket.
    *
    * @return 卡券api_ticket
    * @see #getCardApiTicket(boolean)
@@ -61,7 +63,7 @@ public class WxMpCardServiceImpl implements WxMpCardService {
 
   /**
    * <pre>
-   * 获得卡券api_ticket
+   * 获得卡券api_ticket.
    * 获得时会检查卡券apiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干
    *
    * 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD
@@ -74,26 +76,28 @@ public class WxMpCardServiceImpl implements WxMpCardService {
    */
   @Override
   public String getCardApiTicket(boolean forceRefresh) throws WxErrorException {
-    Lock lock = getWxMpService().getWxMpConfigStorage().getCardApiTicketLock();
+    final TicketType type = TicketType.WX_CARD;
+    Lock lock = getWxMpService().getWxMpConfigStorage().getTicketLock(type);
     try {
       lock.lock();
 
       if (forceRefresh) {
-        this.getWxMpService().getWxMpConfigStorage().expireCardApiTicket();
+        this.getWxMpService().getWxMpConfigStorage().expireTicket(type);
       }
 
-      if (this.getWxMpService().getWxMpConfigStorage().isCardApiTicketExpired()) {
-        String responseContent = this.wxMpService.execute(SimpleGetRequestExecutor.create(this.getWxMpService().getRequestHttp()), CARD_GET_TICKET, null);
+      if (this.getWxMpService().getWxMpConfigStorage().isTicketExpired(type)) {
+        String responseContent = this.wxMpService.execute(SimpleGetRequestExecutor
+          .create(this.getWxMpService().getRequestHttp()), CARD_GET_TICKET, 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.getWxMpService().getWxMpConfigStorage().updateCardApiTicket(cardApiTicket, expiresInSeconds);
+        this.getWxMpService().getWxMpConfigStorage().updateTicket(type, cardApiTicket, expiresInSeconds);
       }
     } finally {
       lock.unlock();
     }
-    return this.getWxMpService().getWxMpConfigStorage().getCardApiTicket();
+    return this.getWxMpService().getWxMpConfigStorage().getTicket(type);
   }
 
   /**
@@ -147,7 +151,7 @@ public class WxMpCardServiceImpl implements WxMpCardService {
   }
 
   /**
-   * 卡券Code查询
+   * 卡券Code查询.
    *
    * @param cardId       卡券ID代表一类卡券
    * @param code         单张卡券的唯一标准
@@ -247,11 +251,11 @@ public class WxMpCardServiceImpl implements WxMpCardService {
   }
 
   /**
-   * 添加测试白名单
+   * 添加测试白名单.
    *
    * @param openid 用户的openid
-   * @return
    */
+  @Override
   public String addTestWhiteList(String openid) throws WxErrorException {
     JsonArray array = new JsonArray();
     array.add(openid);
@@ -262,25 +266,21 @@ public class WxMpCardServiceImpl implements WxMpCardService {
   }
 
   /**
-   * 创建卡券二维码
-   *
-   * @param cardId
-   * @param outerStr
-   * @return
+   * 创建卡券二维码.
    */
+  @Override
   public WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr) throws WxErrorException {
     return createQrcodeCard(cardId, outerStr, 0);
   }
 
   /**
-   * 创建卡券二维码
+   * 创建卡券二维码.
    *
    * @param cardId    卡券编号
    * @param outerStr  二维码标识
    * @param expiresIn 失效时间,单位秒,不填默认365天
-   * @return
-   * @throws WxErrorException
    */
+  @Override
   public WxMpCardQrcodeCreateResult createQrcodeCard(String cardId, String outerStr, int expiresIn) throws WxErrorException {
     JsonObject jsonObject = new JsonObject();
     jsonObject.addProperty("action_name", "QR_CARD");
@@ -293,16 +293,11 @@ public class WxMpCardServiceImpl implements WxMpCardService {
     cardJson.addProperty("outer_str", outerStr);
     actionInfoJson.add("card", cardJson);
     jsonObject.add("action_info", actionInfoJson);
-    String response = this.wxMpService.post(CARD_QRCODE_CREATE, GSON.toJson(jsonObject));
-    return WxMpCardQrcodeCreateResult.fromJson(response);
+    return WxMpCardQrcodeCreateResult.fromJson(this.wxMpService.post(CARD_QRCODE_CREATE, GSON.toJson(jsonObject)));
   }
 
   /**
-   * 创建卡券货架接口
-   *
-   * @param request
-   * @return
-   * @throws WxErrorException
+   * 创建卡券货架接口.
    */
   @Override
   public WxMpCardLandingPageCreateResult createLandingPage(WxMpCardLandingPageCreateRequest request) throws WxErrorException {
@@ -311,24 +306,22 @@ public class WxMpCardServiceImpl implements WxMpCardService {
   }
 
   /**
-   * 将用户的卡券设置为失效状态
+   * 将用户的卡券设置为失效状态.
    * 详见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1451025272&anchor=9
    *
    * @param cardId 卡券编号
    * @param code   用户会员卡号
    * @param reason 设置为失效的原因
-   * @return
-   * @throws WxErrorException
    */
   @Override
   public String unavailableCardCode(String cardId, String code, String reason) throws WxErrorException {
-    if (StringUtils.isAnyBlank(cardId, code, reason))
+    if (StringUtils.isAnyBlank(cardId, code, reason)) {
       throw new WxErrorException(WxError.builder().errorCode(41012).errorMsg("参数不完整").build());
+    }
     JsonObject jsonRequest = new JsonObject();
     jsonRequest.addProperty("card_id", cardId);
     jsonRequest.addProperty("code", code);
     jsonRequest.addProperty("reason", reason);
-    String response = this.wxMpService.post(CARD_CODE_UNAVAILABLE, GSON.toJson(jsonRequest));
-    return response;
+    return this.wxMpService.post(CARD_CODE_UNAVAILABLE, GSON.toJson(jsonRequest));
   }
 }

+ 35 - 0
weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/TicketType.java

@@ -0,0 +1,35 @@
+package me.chanjar.weixin.mp.enums;
+
+import lombok.Getter;
+
+/**
+ * <pre>
+ * ticket类型枚举
+ * Created by Binary Wang on 2018/11/18.
+ * </pre>
+ *
+ * @author <a href="https://github.com/binarywang">Binary Wang</a>
+ */
+@Getter
+public enum TicketType {
+  /**
+   * jsapi
+   */
+  JSAPI("jsapi"),
+  /**
+   * sdk
+   */
+  SDK("2"),
+  /**
+   * 微信卡券
+   */
+  WX_CARD("wx_card");
+  /**
+   * type代码
+   */
+  private String code;
+
+  TicketType(String code) {
+    this.code = code;
+  }
+}

+ 0 - 38
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/WxMpBaseAPITest.java

@@ -1,38 +0,0 @@
-package me.chanjar.weixin.mp.api;
-
-import com.google.inject.Inject;
-import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.mp.api.test.ApiTestModule;
-import org.apache.commons.lang3.StringUtils;
-import org.testng.*;
-import org.testng.annotations.*;
-
-/**
- * 基础API测试
- *
- * @author chanjarster
- */
-@Test(groups = "baseAPI")
-@Guice(modules = ApiTestModule.class)
-public class WxMpBaseAPITest {
-
-  @Inject
-  protected WxMpService wxService;
-
-  public void testRefreshAccessToken() throws WxErrorException {
-    WxMpConfigStorage configStorage = this.wxService.getWxMpConfigStorage();
-    String before = configStorage.getAccessToken();
-    this.wxService.getAccessToken(false);
-
-    String after = configStorage.getAccessToken();
-    Assert.assertNotEquals(before, after);
-    Assert.assertTrue(StringUtils.isNotBlank(after));
-  }
-
-  public void testJsapiTicket() throws WxErrorException {
-    String jsapiTicket = this.wxService.getJsapiTicket(false);
-    System.out.println(jsapiTicket);
-    Assert.assertNotNull(jsapiTicket);
-  }
-
-}

+ 21 - 2
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImplTest.java

@@ -1,14 +1,18 @@
 package me.chanjar.weixin.mp.api.impl;
 
+import org.apache.commons.lang3.StringUtils;
+import org.testng.*;
+import org.testng.annotations.*;
+
 import com.google.inject.Inject;
 import me.chanjar.weixin.common.api.WxConsts;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.mp.api.WxMpConfigStorage;
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.api.test.ApiTestModule;
 import me.chanjar.weixin.mp.api.test.TestConfigStorage;
 import me.chanjar.weixin.mp.bean.result.WxMpCurrentAutoReplyInfo;
-import org.testng.*;
-import org.testng.annotations.*;
+import me.chanjar.weixin.mp.enums.TicketType;
 
 import static org.testng.Assert.*;
 
@@ -40,4 +44,19 @@ public class WxMpServiceImplTest {
     System.out.println(qrConnectUrl);
   }
 
+  public void testGetTicket() throws WxErrorException {
+    String ticket = this.wxService.getTicket(TicketType.SDK, false);
+    System.out.println(ticket);
+    Assert.assertNotNull(ticket);
+  }
+
+  public void testRefreshAccessToken() throws WxErrorException {
+    WxMpConfigStorage configStorage = this.wxService.getWxMpConfigStorage();
+    String before = configStorage.getAccessToken();
+    this.wxService.getAccessToken(false);
+
+    String after = configStorage.getAccessToken();
+    Assert.assertNotEquals(before, after);
+    Assert.assertTrue(StringUtils.isNotBlank(after));
+  }
 }

+ 4 - 9
weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/WxMpDemoInMemoryConfigStorage.java

@@ -1,18 +1,19 @@
 package me.chanjar.weixin.mp.demo;
 
+import java.io.InputStream;
+import java.util.concurrent.locks.ReentrantLock;
+
 import com.thoughtworks.xstream.XStream;
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import me.chanjar.weixin.common.util.xml.XStreamInitializer;
 import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage;
 
-import java.io.InputStream;
-import java.util.concurrent.locks.ReentrantLock;
-
 /**
  * @author Daniel Qian
  */
 @XStreamAlias("xml")
 class WxMpDemoInMemoryConfigStorage extends WxMpInMemoryConfigStorage {
+  private static final long serialVersionUID = -3706236839197109704L;
 
   public static WxMpDemoInMemoryConfigStorage fromXml(InputStream is) {
     XStream xstream = XStreamInitializer.getInstance();
@@ -24,10 +25,4 @@ class WxMpDemoInMemoryConfigStorage extends WxMpInMemoryConfigStorage {
     return wxMpDemoInMemoryConfigStorage;
   }
 
-  @Override
-  public String toString() {
-    return "SimpleWxConfigProvider [appId=" + this.appId + ", secret=" + this.secret + ", accessToken=" + this.accessToken
-      + ", expiresTime=" + this.expiresTime + ", token=" + this.token + ", aesKey=" + this.aesKey + ", templateId=" + this.templateId + "]";
-  }
-
 }

+ 26 - 0
weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java

@@ -11,6 +11,7 @@ import cn.binarywang.wx.miniapp.config.WxMaConfig;
 import me.chanjar.weixin.common.bean.WxAccessToken;
 import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
 import me.chanjar.weixin.mp.api.WxMpConfigStorage;
+import me.chanjar.weixin.mp.enums.TicketType;
 import me.chanjar.weixin.open.api.WxOpenConfigStorage;
 import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken;
 import me.chanjar.weixin.open.bean.WxOpenComponentAccessToken;
@@ -323,6 +324,31 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage {
     }
 
     @Override
+    public String getTicket(TicketType type) {
+      return null;
+    }
+
+    @Override
+    public Lock getTicketLock(TicketType type) {
+      return null;
+    }
+
+    @Override
+    public boolean isTicketExpired(TicketType type) {
+      return false;
+    }
+
+    @Override
+    public void expireTicket(TicketType type) {
+
+    }
+
+    @Override
+    public void updateTicket(TicketType type, String ticket, int expiresInSeconds) {
+
+    }
+
+    @Override
     public String getAppid() {
       return this.appId;
     }