mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2025-08-24 07:23:01 +08:00
#844 整合优化ticket管理相关接口代码,方便获取sdk_ticket、jsapi_ticket和card_api_ticket等。
This commit is contained in:
parent
1cd06082aa
commit
49633cd123
@ -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();
|
||||
String getTicket(TicketType type);
|
||||
|
||||
Lock getJsapiTicketLock();
|
||||
Lock getTicketLock(TicketType type);
|
||||
|
||||
boolean isJsapiTicketExpired();
|
||||
boolean isTicketExpired(TicketType type);
|
||||
|
||||
/**
|
||||
* 强制将jsapi ticket过期掉
|
||||
* 强制将ticket过期掉.
|
||||
*/
|
||||
void expireJsapiTicket();
|
||||
void expireTicket(TicketType type);
|
||||
|
||||
/**
|
||||
* 更新ticket.
|
||||
* 应该是线程安全的
|
||||
*
|
||||
* @param jsapiTicket 新的jsapi ticket值
|
||||
* @param type ticket类型
|
||||
* @param ticket 新的ticket值
|
||||
* @param expiresInSeconds 过期时间,以秒为单位
|
||||
*/
|
||||
void updateJsapiTicket(String jsapiTicket, int expiresInSeconds);
|
||||
|
||||
String getCardApiTicket();
|
||||
|
||||
Lock getCardApiTicketLock();
|
||||
|
||||
boolean isCardApiTicketExpired();
|
||||
|
||||
/**
|
||||
* 强制将卡券api ticket过期掉
|
||||
*/
|
||||
void expireCardApiTicket();
|
||||
|
||||
/**
|
||||
* 应该是线程安全的
|
||||
*
|
||||
* @param cardApiTicket 新的cardApi 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();
|
||||
|
||||
|
@ -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,34 +38,21 @@ 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 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 setJsapiTicket(String jsapiTicket) {
|
||||
this.jsapiTicket = jsapiTicket;
|
||||
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 getJsapiTicketLock() {
|
||||
return this.jsapiTicketLock;
|
||||
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 isJsapiTicketExpired() {
|
||||
return System.currentTimeMillis() > this.jsapiTicketExpiresTime;
|
||||
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 updateJsapiTicket(String jsapiTicket, int expiresInSeconds) {
|
||||
this.jsapiTicket = jsapiTicket;
|
||||
// 预留200秒的时间
|
||||
this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
|
||||
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 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 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
|
||||
@ -251,40 +174,6 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
|
||||
return WxMpGsonBuilder.create().toJson(this);
|
||||
}
|
||||
|
||||
@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;
|
||||
|
@ -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() {
|
||||
public String getTicket(TicketType type) {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
return jedis.get(this.jsapiTicketKey);
|
||||
return jedis.get(this.getTicketRedisKey(type));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJsapiTicketExpired() {
|
||||
public boolean isTicketExpired(TicketType type) {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
return jedis.ttl(this.jsapiTicketKey) < 2;
|
||||
return jedis.ttl(this.getTicketRedisKey(type)) < 2;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) {
|
||||
public synchronized void updateTicket(TicketType type, String jsapiTicket, int expiresInSeconds) {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
jedis.setex(this.jsapiTicketKey, expiresInSeconds - 200, jsapiTicket);
|
||||
jedis.setex(this.getTicketRedisKey(type), expiresInSeconds - 200, jsapiTicket);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expireJsapiTicket() {
|
||||
public void expireTicket(TicketType type) {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
jedis.expire(this.jsapiTicketKey, 0);
|
||||
jedis.expire(this.getTicketRedisKey(type), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCardApiTicket() {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
return jedis.get(this.cardapiTicketKey);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCardApiTicketExpired() {
|
||||
try (Jedis jedis = this.jedisPool.getResource()) {
|
||||
return jedis.ttl(this.cardapiTicketKey) < 2;
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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,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));
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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 + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
@ -322,6 +323,31 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage {
|
||||
wxOpenConfigStorage.updateAuthorizerAccessToken(appId, accessToken, expiresInSeconds);
|
||||
}
|
||||
|
||||
@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;
|
||||
|
Loading…
Reference in New Issue
Block a user