From 98aef34fdb87ed0b4acdf6667b83419dc9d59e7b Mon Sep 17 00:00:00 2001 From: yuanqixun Date: Sun, 3 May 2020 21:29:43 +0800 Subject: [PATCH] =?UTF-8?q?:art:=20#1542=20=E5=B0=8F=E7=A8=8B=E5=BA=8F?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E9=85=8D=E7=BD=AE=E7=B1=BB=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?Redisson=E7=9A=84=E5=AE=9E=E7=8E=B0=EF=BC=8C=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E5=88=86=E5=B8=83=E5=BC=8F=E9=94=81=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 增加Redisson的实现,解决分布式锁问题 * key值重复添加了appid。 Co-authored-by: 袁启勋 --- weixin-java-miniapp/pom.xml | 4 + .../config/impl/WxMaRedissonConfigImpl.java | 153 ++++++++++++++++++ .../impl/WxMaRedissonConfigImplTest.java | 72 +++++++++ 3 files changed, 229 insertions(+) create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaRedissonConfigImpl.java create mode 100644 weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/config/impl/WxMaRedissonConfigImplTest.java diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml index c25c053d9..8180d67c9 100644 --- a/weixin-java-miniapp/pom.xml +++ b/weixin-java-miniapp/pom.xml @@ -80,6 +80,10 @@ org.projectlombok lombok + + org.redisson + redisson + com.github.jedis-lock jedis-lock diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaRedissonConfigImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaRedissonConfigImpl.java new file mode 100644 index 000000000..ef5facb82 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaRedissonConfigImpl.java @@ -0,0 +1,153 @@ +package cn.binarywang.wx.miniapp.config.impl; + +import lombok.NonNull; +import me.chanjar.weixin.common.bean.WxAccessToken; +import me.chanjar.weixin.common.redis.RedissonWxRedisOps; +import me.chanjar.weixin.common.redis.WxRedisOps; +import org.apache.commons.lang3.StringUtils; +import org.redisson.api.RedissonClient; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Lock; + +/** + * 基于Redisson的实现 + * + * @author yuanqixun + * @date 2020/5/3 + */ +public class WxMaRedissonConfigImpl extends WxMaDefaultConfigImpl { + + protected final static String LOCK_KEY = "wechat_ma_lock:"; + protected final static String MA_ACCESS_TOKEN_KEY = "wechat_ma_access_token_key:"; + protected final static String MA_JSAPI_TICKET_KEY = "wechat_ma_jsapi_ticket_key:"; + protected final static String MA_CARD_API_TICKET_KEY = "wechat_ma_card_api_ticket_key:"; + + /** + * redis 存储的 key 的前缀,可为空 + */ + /** + * redis 存储的 key 的前缀,可为空 + */ + protected String keyPrefix; + protected String accessTokenKey; + protected String jsapiTicketKey; + protected String cardApiTicketKey; + protected String lockKey; + + private final WxRedisOps redisOps; + + public WxMaRedissonConfigImpl(@NonNull RedissonClient redissonClient, String keyPrefix) { + this(new RedissonWxRedisOps(redissonClient), keyPrefix); + } + + public WxMaRedissonConfigImpl(@NonNull RedissonClient redissonClient) { + this(redissonClient, null); + } + + private WxMaRedissonConfigImpl(@NonNull WxRedisOps redisOps, String keyPrefix) { + this.redisOps = redisOps; + this.keyPrefix = keyPrefix; + } + + @Override + public void setAppid(String appid) { + super.setAppid(appid); + String prefix = StringUtils.isBlank(keyPrefix) ? "" : + (StringUtils.endsWith(keyPrefix, ":") ? keyPrefix : (keyPrefix + ":")); + lockKey = prefix + LOCK_KEY.concat(appid); + accessTokenKey = prefix + MA_ACCESS_TOKEN_KEY.concat(appid); + jsapiTicketKey = prefix + MA_JSAPI_TICKET_KEY.concat(appid); + cardApiTicketKey = prefix + MA_CARD_API_TICKET_KEY.concat(appid); + } + + protected Lock getLockByKey(String key) { + return redisOps.getLock(key); + } + + @Override + public Lock getAccessTokenLock() { + return getLockByKey(this.lockKey.concat(":").concat("accessToken")); + } + + @Override + public Lock getCardApiTicketLock() { + return getLockByKey(this.lockKey.concat(":").concat("cardApiTicket")); + + } + + @Override + public Lock getJsapiTicketLock() { + return getLockByKey(this.lockKey.concat(":").concat("jsapiTicket")); + } + + @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 void updateAccessToken(WxAccessToken accessToken) { + redisOps.setValue(this.accessTokenKey, accessToken.getAccessToken(), accessToken.getExpiresIn(), TimeUnit.SECONDS); + } + + @Override + public void updateAccessToken(String accessToken, int expiresInSeconds) { + redisOps.setValue(this.accessTokenKey, accessToken, expiresInSeconds, TimeUnit.SECONDS); + } + + @Override + public String getJsapiTicket() { + return redisOps.getValue(this.jsapiTicketKey); + } + + @Override + public boolean isJsapiTicketExpired() { + Long expire = redisOps.getExpire(this.jsapiTicketKey); + return expire == null || expire < 2; + } + + @Override + public void expireJsapiTicket() { + redisOps.expire(this.jsapiTicketKey, 0, TimeUnit.SECONDS); + } + + @Override + public void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) { + redisOps.setValue(this.jsapiTicketKey, jsapiTicket, expiresInSeconds, TimeUnit.SECONDS); + + } + + @Override + public String getCardApiTicket() { + return redisOps.getValue(cardApiTicketKey); + } + + @Override + public boolean isCardApiTicketExpired() { + Long expire = redisOps.getExpire(this.cardApiTicketKey); + return expire == null || expire < 2; + } + + @Override + public void expireCardApiTicket() { + redisOps.expire(this.cardApiTicketKey, 0, TimeUnit.SECONDS); + } + + @Override + public void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) { + redisOps.setValue(this.cardApiTicketKey, cardApiTicket, expiresInSeconds, TimeUnit.SECONDS); + } + + @Override + public void expireAccessToken() { + redisOps.expire(this.accessTokenKey, 0, TimeUnit.SECONDS); + } + +} diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/config/impl/WxMaRedissonConfigImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/config/impl/WxMaRedissonConfigImplTest.java new file mode 100644 index 000000000..d4fb45963 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/config/impl/WxMaRedissonConfigImplTest.java @@ -0,0 +1,72 @@ +package cn.binarywang.wx.miniapp.config.impl; + +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import lombok.SneakyThrows; +import org.redisson.Redisson; +import org.redisson.api.RedissonClient; +import org.redisson.config.Config; +import org.redisson.config.TransportMode; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +/** + * @author yqx + * @date 2020/5/3 + */ +public class WxMaRedissonConfigImplTest { + + WxMaDefaultConfigImpl wxMaConfig; + + @BeforeMethod + public void setUp() { + Config config = new Config(); + config.useSingleServer().setAddress("redis://127.0.0.1:6379") + .setDatabase(0); + config.setTransportMode(TransportMode.NIO); + RedissonClient redisson = Redisson.create(config); + wxMaConfig = new WxMaRedissonConfigImpl(redisson); + wxMaConfig.setAppid("appid12345678"); + wxMaConfig.updateAccessToken("accessToken", 5); //有效期5秒 + wxMaConfig.updateJsapiTicket("jsapiTicket", 5); + wxMaConfig.updateCardApiTicket("cardApiTicket", 5); + } + + @SneakyThrows + @Test + public void testGetAccessToken() { + String accessToken = wxMaConfig.getAccessToken(); + Assert.assertEquals(accessToken, "accessToken"); + Assert.assertFalse(wxMaConfig.isAccessTokenExpired()); + Thread.sleep(6000);//休眠6s + Assert.assertTrue(wxMaConfig.isAccessTokenExpired()); + } + + @SneakyThrows + @Test + public void testGetJsapiTicket() { + String jsapiTicket = wxMaConfig.getJsapiTicket(); + Assert.assertEquals(jsapiTicket, "jsapiTicket"); + Assert.assertFalse(wxMaConfig.isJsapiTicketExpired()); + Thread.sleep(6000);//休眠6s + Assert.assertTrue(wxMaConfig.isJsapiTicketExpired()); + } + + @SneakyThrows + @Test + public void testGetCardApiTicket() { + String cardApiTicket = wxMaConfig.getCardApiTicket(); + Assert.assertEquals(cardApiTicket, "cardApiTicket"); + Assert.assertFalse(wxMaConfig.isCardApiTicketExpired()); + Thread.sleep(6000);//休眠6s + Assert.assertTrue(wxMaConfig.isCardApiTicketExpired()); + } + + @Test + public void testIsAccessTokenExpired() { + Assert.assertFalse(wxMaConfig.isAccessTokenExpired()); + wxMaConfig.expireAccessToken(); + Assert.assertTrue(wxMaConfig.isAccessTokenExpired()); + } +}