diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/AbstractWxMaRedisConfig.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/AbstractWxMaRedisConfig.java new file mode 100644 index 00000000..ac75b369 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/AbstractWxMaRedisConfig.java @@ -0,0 +1,280 @@ +package cn.binarywang.wx.miniapp.config.impl; + +import com.github.jedis.lock.JedisLock; +import redis.clients.jedis.Jedis; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; + +/** + * @author winter + */ +public abstract class AbstractWxMaRedisConfig extends WxMaDefaultConfigImpl { + + public interface JedisConfig { + Jedis config(Jedis jedis); + } + + private static final String ACCESS_TOKEN = "accessToken"; + private static final String JSAPI_TICKET = "jsapiTicket"; + private static final String CARD_API_TICKET = "cardApiTicket"; + + private static final String HASH_VALUE_FIELD = "value"; + private static final String HASH_EXPIRE_FIELD = "expire"; + + /** + * Redis Key 的前缀,默认为 maConfig + */ + private String redisKeyPrefix = "maConfig"; + + /** + * 微信小程序唯一id,用于拼接存储到redis时的key,防止key重复. + */ + private String maId; + + private Lock accessTokenLock; + private Lock jsapiTicketLock; + private Lock cardApiTicketLock; + + /** + * 临时文件目录. + */ + protected volatile File tmpDirFile; + + /** + * 对从 JedisPool.getResource() 获取到的每个 Jedis 实例进行配置 + */ + private JedisConfig jedisConfig; + + protected abstract Jedis getJedis(); + + private Jedis getConfiguredJedis() { + Jedis jedis = getJedis(); + if (jedisConfig != null) { + return jedisConfig.config(jedis); + } else { + return jedis; + } + } + + private String getRedisKey(String key) { + StringBuilder redisKey = new StringBuilder(redisKeyPrefix).append(":"); + if (maId == null) { + return redisKey.append(key).toString(); + } else { + return redisKey.append(maId).append(":").append(key).toString(); + } + } + + private String getValueFromRedis(String key) { + try (Jedis jedis = getConfiguredJedis()) { + return jedis.hget(getRedisKey(key), HASH_VALUE_FIELD); + } + } + + private void setValueToRedis(String key, long expiresTime, String value) { + try (Jedis jedis = getConfiguredJedis()) { + Map hash = new HashMap(); + hash.put(HASH_VALUE_FIELD, value); + hash.put(HASH_EXPIRE_FIELD, String.valueOf(expiresTime)); + jedis.hmset(getRedisKey(key), hash); + } + } + + private long getExpireFromRedis(String key) { + try (Jedis jedis = getConfiguredJedis()) { + String expire = jedis.hget(getRedisKey(key), HASH_EXPIRE_FIELD); + return expire == null ? 0 : Long.parseLong(expire); + } + } + + private void setExpire(String key, long expiresTime) { + try (Jedis jedis = getConfiguredJedis()) { + jedis.hset(getRedisKey(key), HASH_EXPIRE_FIELD, String.valueOf(expiresTime)); + } + } + + public void setRedisKeyPrefix(String redisKeyPrefix) { + this.redisKeyPrefix = redisKeyPrefix; + } + + public void setJedisConfig(JedisConfig jedisConfig) { + this.jedisConfig = jedisConfig; + } + + public void setMaId(String maId) { + this.maId = maId; + } + + @Override + public String getAccessToken() { + return getValueFromRedis(ACCESS_TOKEN); + } + + @Override + public Lock getAccessTokenLock() { + if (accessTokenLock == null) { + synchronized (this) { + if (accessTokenLock == null) { + accessTokenLock = new DistributedLock(getRedisKey("accessTokenLock")); + } + } + } + return accessTokenLock; + } + + @Override + public boolean isAccessTokenExpired() { + return isExpired(getExpireFromRedis(ACCESS_TOKEN)); + } + + @Override + public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { + setValueToRedis(ACCESS_TOKEN, expiresAheadInMillis(expiresInSeconds), accessToken); + } + + @Override + public String getJsapiTicket() { + return getValueFromRedis(JSAPI_TICKET); + } + + @Override + public Lock getJsapiTicketLock() { + if (jsapiTicketLock == null) { + synchronized (this) { + if (jsapiTicketLock == null) { + jsapiTicketLock = new DistributedLock(getRedisKey("jsapiTicketLock")); + } + } + } + return jsapiTicketLock; + } + + @Override + public boolean isJsapiTicketExpired() { + return isExpired(getExpireFromRedis(JSAPI_TICKET)); + } + + @Override + public void expireJsapiTicket() { + setExpire(JSAPI_TICKET, 0); + } + + @Override + public void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { + setValueToRedis(JSAPI_TICKET, expiresAheadInMillis(expiresInSeconds), jsapiTicket); + } + + + @Override + public String getCardApiTicket() { + return getValueFromRedis(CARD_API_TICKET); + } + + @Override + public Lock getCardApiTicketLock() { + if (cardApiTicketLock == null) { + synchronized (this) { + if (cardApiTicketLock == null) { + cardApiTicketLock = new DistributedLock(getRedisKey("cardApiTicketLock")); + } + } + } + return cardApiTicketLock; + } + + @Override + public boolean isCardApiTicketExpired() { + return isExpired(getExpireFromRedis(CARD_API_TICKET)); + } + + @Override + public void expireCardApiTicket() { + setExpire(CARD_API_TICKET, 0); + } + + @Override + public void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) { + setValueToRedis(CARD_API_TICKET, expiresAheadInMillis(expiresInSeconds), cardApiTicket); + } + + @Override + public void expireAccessToken() { + setExpiresTime(0); + } + + @Override + public long getExpiresTime() { + return getExpireFromRedis(ACCESS_TOKEN); + } + + @Override + public void setExpiresTime(long expiresTime) { + setExpire(ACCESS_TOKEN, expiresTime); + } + + /** + * 基于redis的简单分布式锁. + */ + private class DistributedLock implements Lock { + + private JedisLock lock; + + private DistributedLock(String key) { + this.lock = new JedisLock(getRedisKey(key)); + } + + @Override + public void lock() { + try (Jedis jedis = getConfiguredJedis()) { + if (!lock.acquire(jedis)) { + throw new RuntimeException("acquire timeouted"); + } + } catch (InterruptedException e) { + throw new RuntimeException("lock failed", e); + } + } + + @Override + public void lockInterruptibly() throws InterruptedException { + try (Jedis jedis = getConfiguredJedis()) { + if (!lock.acquire(jedis)) { + throw new RuntimeException("acquire timeouted"); + } + } + } + + @Override + public boolean tryLock() { + try (Jedis jedis = getConfiguredJedis()) { + return lock.acquire(jedis); + } catch (InterruptedException e) { + throw new RuntimeException("lock failed", e); + } + } + + @Override + public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { + try (Jedis jedis = getConfiguredJedis()) { + return lock.acquire(jedis); + } + } + + @Override + public void unlock() { + try (Jedis jedis = getConfiguredJedis()) { + lock.release(jedis); + } + } + + @Override + public Condition newCondition() { + throw new RuntimeException("unsupported method"); + } + + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaDefaultConfigImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaDefaultConfigImpl.java index 76ff7611..98929be1 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaDefaultConfigImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaDefaultConfigImpl.java @@ -48,6 +48,20 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; + /** + * 会过期的数据提前过期时间,默认预留200秒的时间 + */ + protected long expiresAheadInMillis(int expiresInSeconds) { + return System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; + } + + /** + * 判断 expiresTime 是否已经过期 + */ + protected boolean isExpired(long expiresTime) { + return System.currentTimeMillis() > expiresTime; + } + @Override public String getAccessToken() { return this.accessToken; @@ -68,7 +82,7 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { @Override public boolean isAccessTokenExpired() { - return System.currentTimeMillis() > this.expiresTime; + return isExpired(this.expiresTime); } @Override @@ -78,8 +92,8 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { @Override public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { - this.accessToken = accessToken; - this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; + setAccessToken(accessToken); + setExpiresTime(expiresAheadInMillis(expiresInSeconds)); } @Override @@ -94,7 +108,7 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { @Override public boolean isJsapiTicketExpired() { - return System.currentTimeMillis() > this.jsapiTicketExpiresTime; + return isExpired(this.jsapiTicketExpiresTime); } @Override @@ -105,8 +119,7 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { @Override public void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { this.jsapiTicket = jsapiTicket; - // 预留200秒的时间 - this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; + this.jsapiTicketExpiresTime = expiresAheadInMillis(expiresInSeconds); } @@ -122,7 +135,7 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { @Override public boolean isCardApiTicketExpired() { - return System.currentTimeMillis() > this.cardApiTicketExpiresTime; + return isExpired(this.cardApiTicketExpiresTime); } @Override @@ -133,8 +146,7 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { @Override public void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) { this.cardApiTicket = cardApiTicket; - // 预留200秒的时间 - this.cardApiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; + this.cardApiTicketExpiresTime = expiresAheadInMillis(expiresInSeconds); } @Override diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaRedisConfigImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaRedisConfigImpl.java index c9340f8d..dfff1cee 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaRedisConfigImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaRedisConfigImpl.java @@ -1,377 +1,40 @@ package cn.binarywang.wx.miniapp.config.impl; -import java.io.File; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; - -import cn.binarywang.wx.miniapp.config.WxMaConfig; -import com.github.jedis.lock.JedisLock; - -import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; -import me.chanjar.weixin.common.bean.WxAccessToken; -import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; /** - * 基于Redis的微信配置provider. + * 基于Redis的微信配置provider. 使用连接池 JedisPool 进行 Redis 操作。 * *
  * 需要引入依赖jedis-lock,才能使用该类。
  * 
- * - * @author winter */ -public class WxMaRedisConfigImpl implements WxMaConfig { - private static final String ACCESS_TOKEN = "accessToken"; - private static final String JSAPI_TICKET = "jsapiTicket"; - private static final String CARD_API_TICKET = "cardApiTicket"; - - private static final String HASH_VALUE_FIELD = "value"; - private static final String HASH_EXPIRE_FIELD = "expire"; +public class WxMaRedisConfigImpl extends AbstractWxMaRedisConfig { private JedisPool jedisPool; - /** - * 微信小程序唯一id,用于拼接存储到redis时的key,防止key重复. - */ - private String maId; - - private volatile String msgDataFormat; - protected volatile String appid; - private volatile String secret; - protected volatile String token; - private volatile String aesKey; - - private volatile String httpProxyHost; - private volatile int httpProxyPort; - private volatile String httpProxyUsername; - private volatile String httpProxyPassword; - - private Lock accessTokenLock; - private Lock jsapiTicketLock; - private Lock cardApiTicketLock; /** - * 临时文件目录. + * JedisPool 在此配置类是必须项,使用 WxMaRedisConfigImpl(JedisPool) 构造方法来构造实例 */ - protected volatile File tmpDirFile; - - private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; - - private String getRedisKey(String key) { - StringBuilder redisKey = new StringBuilder("maConfig:"); - if (maId == null) { - return redisKey.append(key).toString(); - } else { - return redisKey.append(maId).append(":").append(key).toString(); - } + @Deprecated + public WxMaRedisConfigImpl() { } - private String getValueFromRedis(String key) { - try (Jedis jedis = jedisPool.getResource()) { - return jedis.hget(getRedisKey(key), HASH_VALUE_FIELD); - } - } - - private void setValueToRedis(String key, long expiresTime, String value) { - try (Jedis jedis = jedisPool.getResource()) { - Map hash = new HashMap(); - hash.put(HASH_VALUE_FIELD, value); - hash.put(HASH_EXPIRE_FIELD, String.valueOf(expiresTime)); - jedis.hmset(getRedisKey(key), hash); - } - } - - private long getExpireFromRedis(String key) { - try (Jedis jedis = jedisPool.getResource()) { - String expire = jedis.hget(getRedisKey(key), HASH_EXPIRE_FIELD); - return expire == null ? 0 : Long.parseLong(expire); - } - } - - private void setExpire(String key, long expiresTime) { - try (Jedis jedis = jedisPool.getResource()) { - jedis.hset(getRedisKey(key), HASH_EXPIRE_FIELD, String.valueOf(expiresTime)); - } + public WxMaRedisConfigImpl(JedisPool jedisPool) { + this.jedisPool = jedisPool; } + /** + * 使用 WxMaRedisConfigImpl(JedisPool) 构造方法来设置 JedisPool + */ + @Deprecated public void setJedisPool(JedisPool jedisPool) { this.jedisPool = jedisPool; } - public void setMaId(String maId) { - this.maId = maId; - } - - @Override - public String getAccessToken() { - return getValueFromRedis(ACCESS_TOKEN); - } - - @Override - public Lock getAccessTokenLock() { - if (accessTokenLock == null) { - synchronized (this) { - if (accessTokenLock == null) { - accessTokenLock = new DistributedLock(getRedisKey("accessTokenLock")); - } - } - } - return accessTokenLock; - } - - @Override - public boolean isAccessTokenExpired() { - return System.currentTimeMillis() > getExpireFromRedis(ACCESS_TOKEN); - } - - @Override - public synchronized void updateAccessToken(WxAccessToken accessToken) { - updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn()); - } - - @Override - public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { - setValueToRedis(ACCESS_TOKEN, System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L, accessToken); - } - - @Override - public String getJsapiTicket() { - return getValueFromRedis(JSAPI_TICKET); - } - - @Override - public Lock getJsapiTicketLock() { - if (jsapiTicketLock == null) { - synchronized (this) { - if (jsapiTicketLock == null) { - jsapiTicketLock = new DistributedLock(getRedisKey("jsapiTicketLock")); - } - } - } - return jsapiTicketLock; - } - - @Override - public boolean isJsapiTicketExpired() { - return System.currentTimeMillis() > getExpireFromRedis(JSAPI_TICKET); - } - - @Override - public void expireJsapiTicket() { - setExpire(JSAPI_TICKET, 0); - } - - @Override - public void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { - // 预留200秒的时间 - setValueToRedis(JSAPI_TICKET, System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L, jsapiTicket); - } - - - @Override - public String getCardApiTicket() { - return getValueFromRedis(CARD_API_TICKET); - } - - @Override - public Lock getCardApiTicketLock() { - if (cardApiTicketLock == null) { - synchronized (this) { - if (cardApiTicketLock == null) { - cardApiTicketLock = new DistributedLock(getRedisKey("cardApiTicketLock")); - } - } - } - return cardApiTicketLock; - } - - @Override - public boolean isCardApiTicketExpired() { - return System.currentTimeMillis() > getExpireFromRedis(CARD_API_TICKET); - } - - @Override - public void expireCardApiTicket() { - setExpire(CARD_API_TICKET, 0); - } - - @Override - public void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) { - setValueToRedis(CARD_API_TICKET, System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L, cardApiTicket); - } - - @Override - public void expireAccessToken() { - setExpire(ACCESS_TOKEN, 0); - } - - @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 long getExpiresTime() { - return getExpireFromRedis(ACCESS_TOKEN); - } - - @Override - public String getAesKey() { - return this.aesKey; - } - - public void setAesKey(String aesKey) { - this.aesKey = aesKey; - } - - @Override - public String getMsgDataFormat() { - return this.msgDataFormat; - } - - public void setMsgDataFormat(String msgDataFormat) { - this.msgDataFormat = msgDataFormat; - } - - @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; - } - @Override - public String toString() { - return WxMaGsonBuilder.create().toJson(this); - } - - @Override - public ApacheHttpClientBuilder getApacheHttpClientBuilder() { - return this.apacheHttpClientBuilder; - } - - public void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder) { - this.apacheHttpClientBuilder = apacheHttpClientBuilder; - } - - @Override - public boolean autoRefreshToken() { - return true; - } - - @Override - public String getAppid() { - return appid; - } - - public void setAppid(String appid) { - this.appid = appid; - } - - /** - * 基于redis的简单分布式锁. - */ - private class DistributedLock implements Lock { - - private JedisLock lock; - - private DistributedLock(String key) { - this.lock = new JedisLock(getRedisKey(key)); - } - - @Override - public void lock() { - try (Jedis jedis = jedisPool.getResource()) { - if (!lock.acquire(jedis)) { - throw new RuntimeException("acquire timeouted"); - } - } catch (InterruptedException e) { - throw new RuntimeException("lock failed", e); - } - } - - @Override - public void lockInterruptibly() throws InterruptedException { - try (Jedis jedis = jedisPool.getResource()) { - if (!lock.acquire(jedis)) { - throw new RuntimeException("acquire timeouted"); - } - } - } - - @Override - public boolean tryLock() { - try (Jedis jedis = jedisPool.getResource()) { - return lock.acquire(jedis); - } catch (InterruptedException e) { - throw new RuntimeException("lock failed", e); - } - } - - @Override - public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { - try (Jedis jedis = jedisPool.getResource()) { - return lock.acquire(jedis); - } - } - - @Override - public void unlock() { - try (Jedis jedis = jedisPool.getResource()) { - lock.release(jedis); - } - } - - @Override - public Condition newCondition() { - throw new RuntimeException("unsupported method"); - } - + protected Jedis getJedis() { + return jedisPool.getResource(); } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaRedisConnectionConfigImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaRedisConnectionConfigImpl.java new file mode 100644 index 00000000..e48cda20 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaRedisConnectionConfigImpl.java @@ -0,0 +1,24 @@ +package cn.binarywang.wx.miniapp.config.impl; + +import redis.clients.jedis.Jedis; + +/** + * 基于Redis的微信配置provider. 使用自己管理的 Jedis 实例进行 Redis 操作。 + * + *
+ * 需要引入依赖jedis-lock,才能使用该类。
+ * 
+ */ +public class WxMaRedisConnectionConfigImpl extends AbstractWxMaRedisConfig { + + public WxMaRedisConnectionConfigImpl(Jedis jedis) { + this.jedis = jedis; + } + + private Jedis jedis; + + @Override + protected Jedis getJedis() { + return jedis; + } +}