* 非内置实现redis相关操作, 请实现该类 */ -public class BaseWxMpRedisOps implements WxMpRedisOps { +public abstract class BaseWxRedisOps implements WxRedisOps { @Override public String getValue(String key) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/redis/JedisWxMpRedisOps.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/redis/JedisWxRedisOps.java similarity index 82% rename from weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/redis/JedisWxMpRedisOps.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/redis/JedisWxRedisOps.java index 0ba21bcd..0762e67d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/redis/JedisWxMpRedisOps.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/redis/JedisWxRedisOps.java @@ -1,6 +1,6 @@ -package me.chanjar.weixin.mp.config.redis; +package me.chanjar.weixin.common.redis; -import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; import me.chanjar.weixin.common.util.locks.JedisDistributedLock; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; @@ -8,13 +8,10 @@ import redis.clients.jedis.JedisPool; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; -/** - * Jedis实现相关操作 - */ -@AllArgsConstructor -public class JedisWxMpRedisOps implements WxMpRedisOps { +@RequiredArgsConstructor +public class JedisWxRedisOps implements WxRedisOps { - private JedisPool jedisPool; + private final JedisPool jedisPool; @Override public String getValue(String key) { diff --git a/spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/extend/RedisTemplateWxMpRedisOps.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/redis/RedisTemplateWxRedisOps.java similarity index 83% rename from spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/extend/RedisTemplateWxMpRedisOps.java rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/redis/RedisTemplateWxRedisOps.java index 4939aba8..06870328 100644 --- a/spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/extend/RedisTemplateWxMpRedisOps.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/redis/RedisTemplateWxRedisOps.java @@ -1,7 +1,6 @@ -package com.binarywang.spring.starter.wxjava.mp.extend; +package me.chanjar.weixin.common.redis; import lombok.RequiredArgsConstructor; -import me.chanjar.weixin.mp.config.redis.BaseWxMpRedisOps; import org.springframework.data.redis.core.StringRedisTemplate; import java.util.concurrent.TimeUnit; @@ -9,7 +8,7 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @RequiredArgsConstructor -public class RedisTemplateWxMpRedisOps extends BaseWxMpRedisOps { +public class RedisTemplateWxRedisOps implements WxRedisOps { private final StringRedisTemplate redisTemplate; diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/redis/RedissonWxRedisOps.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/redis/RedissonWxRedisOps.java new file mode 100644 index 00000000..e06db302 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/redis/RedissonWxRedisOps.java @@ -0,0 +1,39 @@ +package me.chanjar.weixin.common.redis; + +import lombok.RequiredArgsConstructor; +import org.redisson.api.RedissonClient; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Lock; + +@RequiredArgsConstructor +public class RedissonWxRedisOps implements WxRedisOps { + + private final RedissonClient redissonClient; + + @Override + public String getValue(String key) { + Object value = redissonClient.getBucket(key).get(); + return value == null ? null : value.toString(); + } + + @Override + public void setValue(String key, String value, int expire, TimeUnit timeUnit) { + redissonClient.getBucket(key).set(value, expire, timeUnit); + } + + @Override + public Long getExpire(String key) { + return redissonClient.getBucket(key).remainTimeToLive(); + } + + @Override + public void expire(String key, int expire, TimeUnit timeUnit) { + redissonClient.getBucket(key).expire(expire, timeUnit); + } + + @Override + public Lock getLock(String key) { + return redissonClient.getLock(key); + } +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/redis/WxRedisOps.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/redis/WxRedisOps.java new file mode 100644 index 00000000..5489165e --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/redis/WxRedisOps.java @@ -0,0 +1,27 @@ +package me.chanjar.weixin.common.redis; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Lock; + +/** + * 微信Redis相关操作 + *
+ * 该接口不承诺稳定, 外部实现请继承{@link BaseWxRedisOps} + * + * @see BaseWxRedisOps 实现需要继承该类 + * @see JedisWxRedisOps jedis实现 + * @see RedissonWxRedisOps redisson实现 + * @see RedisTemplateWxRedisOps redisTemplate实现 + */ +public interface WxRedisOps { + + String getValue(String key); + + void setValue(String key, String value, int expire, TimeUnit timeUnit); + + Long getExpire(String key); + + void expire(String key, int expire, TimeUnit timeUnit); + + Lock getLock(String key); +} 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 b75fa711..94e09bc5 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 @@ -46,8 +46,8 @@ public class WxMaDefaultConfigImpl implements WxMaConfig { */ private volatile String cardApiTicket; private volatile long cardApiTicketExpiresTime; - private Lock jsapiTicketLock = new ReentrantLock(); - private Lock cardApiTicketLock = new ReentrantLock(); + protected volatile Lock jsapiTicketLock = new ReentrantLock(); + protected volatile Lock cardApiTicketLock = new ReentrantLock(); private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; /** diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaRedisBetterConfigImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaRedisBetterConfigImpl.java new file mode 100644 index 00000000..e53ed198 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaRedisBetterConfigImpl.java @@ -0,0 +1,130 @@ +package cn.binarywang.wx.miniapp.config.impl; + +import cn.binarywang.wx.miniapp.constant.TicketType; +import me.chanjar.weixin.common.redis.JedisWxRedisOps; +import me.chanjar.weixin.common.redis.WxRedisOps; +import redis.clients.jedis.JedisPool; + +import java.util.concurrent.TimeUnit; + +/** + * 基于redis存储的微信小程序配置类 + */ +public class WxMaRedisBetterConfigImpl extends WxMaDefaultConfigImpl { + private static final String ACCESS_TOKEN_KEY_TPL = "%s:access_token:%s"; + private static final String TICKET_KEY_TPL = "%s:ticket:key:%s:%s"; + private static final String LOCK_KEY_TPL = "%s:lock:%s:"; + + private final WxRedisOps redisOps; + private final String keyPrefix; + + private volatile String accessTokenKey; + private volatile String lockKey; + + public WxMaRedisBetterConfigImpl(JedisPool jedisPool) { + this(new JedisWxRedisOps(jedisPool), "wa"); + } + + public WxMaRedisBetterConfigImpl(WxRedisOps redisOps, String keyPrefix) { + this.redisOps = redisOps; + this.keyPrefix = keyPrefix; + } + + @Override + public void setAppid(String appId) { + super.setAppid(appId); + this.accessTokenKey = String.format(ACCESS_TOKEN_KEY_TPL, this.keyPrefix, appId); + this.lockKey = String.format(LOCK_KEY_TPL, this.keyPrefix, appId); + super.accessTokenLock = this.redisOps.getLock(lockKey.concat("accessTokenLock")); + super.jsapiTicketLock = this.redisOps.getLock(lockKey.concat("jsapiTicketLock")); + super.cardApiTicketLock = this.redisOps.getLock(lockKey.concat("cardApiTicketLock")); + } + + //------------------------------------------------------------------------ + // token相关 + //------------------------------------------------------------------------ + @Override + public String getAccessToken() { + return redisOps.getValue(this.accessTokenKey); + } + + @Override + public boolean isAccessTokenExpired() { + Long expire = redisOps.getExpire(this.accessTokenKey); + return expire == null || expire < 2; + } + + @Override + public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { + redisOps.setValue(this.accessTokenKey, accessToken, expiresInSeconds - 200, TimeUnit.SECONDS); + } + + @Override + public void expireAccessToken() { + redisOps.expire(this.accessTokenKey, 0, TimeUnit.SECONDS); + } + + //------------------------------------------------------------------------ + // ticket相关 + //------------------------------------------------------------------------ + @Override + public String getJsapiTicket() { + return doGetTicket(TicketType.JSAPI); + } + + @Override + public boolean isJsapiTicketExpired() { + return doIsTicketExpired(TicketType.JSAPI); + } + + @Override + public void expireJsapiTicket() { + doExpireTicket(TicketType.JSAPI); + } + + @Override + public synchronized void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { + doUpdateTicket(TicketType.JSAPI, jsapiTicket, expiresInSeconds); + } + + @Override + public String getCardApiTicket() { + return doGetTicket(TicketType.WX_CARD); + } + + @Override + public boolean isCardApiTicketExpired() { + return doIsTicketExpired(TicketType.WX_CARD); + } + + @Override + public void expireCardApiTicket() { + doExpireTicket(TicketType.WX_CARD); + } + + @Override + public synchronized void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) { + doUpdateTicket(TicketType.WX_CARD, cardApiTicket, expiresInSeconds); + } + + private String getTicketRedisKey(TicketType type) { + return String.format(TICKET_KEY_TPL, this.keyPrefix, this.appid, type.getCode()); + } + + private String doGetTicket(TicketType type) { + return redisOps.getValue(this.getTicketRedisKey(type)); + } + + private boolean doIsTicketExpired(TicketType type) { + return redisOps.getExpire(this.getTicketRedisKey(type)) < 2; + } + + private void doUpdateTicket(TicketType type, String ticket, int expiresInSeconds) { + redisOps.setValue(this.getTicketRedisKey(type), ticket, expiresInSeconds - 200, TimeUnit.SECONDS); + } + + private void doExpireTicket(TicketType type) { + redisOps.expire(this.getTicketRedisKey(type), 0, TimeUnit.SECONDS); + } + +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/TicketType.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/TicketType.java new file mode 100644 index 00000000..e8b07de0 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/TicketType.java @@ -0,0 +1,30 @@ +package cn.binarywang.wx.miniapp.constant; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + *
+ * ticket类型枚举 + * Created by Binary Wang on 2018/11/18. + *+ * + * @author Binary Wang + */ +@Getter +@RequiredArgsConstructor +public enum TicketType { + /** + * jsapi + */ + JSAPI("jsapi"), + /** + * 微信卡券 + */ + WX_CARD("wx_card"); + /** + * type代码 + */ + private final String code; + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/impl/WxMpRedisConfigImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/impl/WxMpRedisConfigImpl.java index cbf5eaf3..8460d464 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/impl/WxMpRedisConfigImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/impl/WxMpRedisConfigImpl.java @@ -1,8 +1,8 @@ package me.chanjar.weixin.mp.config.impl; import lombok.Data; -import me.chanjar.weixin.mp.config.redis.JedisWxMpRedisOps; -import me.chanjar.weixin.mp.config.redis.WxMpRedisOps; +import me.chanjar.weixin.common.redis.JedisWxRedisOps; +import me.chanjar.weixin.common.redis.WxRedisOps; import me.chanjar.weixin.mp.enums.TicketType; import redis.clients.jedis.JedisPool; @@ -22,22 +22,22 @@ import java.util.concurrent.TimeUnit; @SuppressWarnings("hiding") public class WxMpRedisConfigImpl extends WxMpDefaultConfigImpl { private static final long serialVersionUID = -988502871997239733L; - + private static final String ACCESS_TOKEN_KEY_TPL = "%s:access_token:%s"; private static final String TICKET_KEY_TPL = "%s:ticket:key:%s:%s"; private static final String LOCK_KEY_TPL = "%s:lock:%s:"; - private final WxMpRedisOps redisOps; + private final WxRedisOps redisOps; private final String keyPrefix; private String accessTokenKey; private String lockKey; public WxMpRedisConfigImpl(JedisPool jedisPool) { - this(new JedisWxMpRedisOps(jedisPool), "wx"); + this(new JedisWxRedisOps(jedisPool), "wx"); } - public WxMpRedisConfigImpl(WxMpRedisOps redisOps, String keyPrefix) { + public WxMpRedisConfigImpl(WxRedisOps redisOps, String keyPrefix) { this.redisOps = redisOps; this.keyPrefix = keyPrefix; } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/redis/WxMpRedisOps.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/redis/WxMpRedisOps.java deleted file mode 100644 index d57d037c..00000000 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/redis/WxMpRedisOps.java +++ /dev/null @@ -1,25 +0,0 @@ -package me.chanjar.weixin.mp.config.redis; - -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Lock; - -/** - * 微信公众号Redis相关操作 - *
- * 该接口不承诺稳定, 外部实现请继承{@link BaseWxMpRedisOps} - * - * @see BaseWxMpRedisOps 实现需要继承该类 - * @see JedisWxMpRedisOps jedis实现 - */ -public interface WxMpRedisOps { - - String getValue(String key); - - void setValue(String key, String value, int expire, TimeUnit timeUnit); - - Long getExpire(String key); - - void expire(String key, int expire, TimeUnit timeUnit); - - Lock getLock(String key); -}