diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/constant/RedisKey.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/constant/RedisKey.java index 0cc9bd0b..e700720f 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/constant/RedisKey.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/constant/RedisKey.java @@ -46,6 +46,8 @@ public class RedisKey { */ public static final String USER_GLM2_TIME_LAST = "userGLM2UseTime:uid_%d"; + public static final String WX_RANDOM_CODE_STRING = "wxRandomCode"; + public static String getKey(String key, Object... objects) { return BASE_KEY + String.format(key, objects); } diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/RedisUtils.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/RedisUtils.java index 415c6764..96b72174 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/RedisUtils.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/RedisUtils.java @@ -32,11 +32,28 @@ public class RedisUtils { " return tonumber(redis.call('INCR',key)) \n" + "end "; + private static final String ZERO_STRING = "0"; public static Long inc(String key, int time, TimeUnit unit) { RedisScript redisScript = new DefaultRedisScript<>(LUA_INCR_EXPIRE, Long.class); return stringRedisTemplate.execute(redisScript, Collections.singletonList(key), String.valueOf(unit.toSeconds(time))); } + /** + * key自增 + * @param key + * @return + */ + public static Long inc(String key) { + return stringRedisTemplate.opsForValue().increment(key); + } + + /** + * 重置key为0 + * @param key + */ + public static void reset(String key) { + stringRedisTemplate.opsForValue().set(key, ZERO_STRING); + } /** * 指定缓存失效时间 * @@ -284,6 +301,66 @@ public static Boolean set(String key, Object value, long time) { } } + /** + * 带if exist缓存放入并设置过期时间 + * + * @param key 键 + * @param value 值 + * @param time 时间 + * @param timeUnit 类型 + * @return true成功 false 失败 + */ + public static Boolean setnx(String key, Object value, long time, TimeUnit timeUnit) { + try { + if (time > 0) { + stringRedisTemplate.opsForValue().setIfAbsent(key, objToStr(value), time, timeUnit); + } else { + set(key, value); + } + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + + /** + * 带if exist缓存放入并设置过期时间 + * + * @param key 键 + * @param value 值 + * @return true成功 false失败 + */ + public static Boolean setnx(String key, Object value, long time) { + try { + if (time > 0) { + stringRedisTemplate.opsForValue().setIfAbsent(key, objToStr(value), time, TimeUnit.SECONDS); + } else { + set(key, value); + } + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + /** + * 带if exist缓存放入 + * + * @param key 键 + * @param value 值 + * @return true成功 false失败 + */ + public static Boolean setnx(String key, Object value) { + try { + stringRedisTemplate.opsForValue().setIfAbsent(key, objToStr(value)); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + return false; + } + } + /** * 普通缓存放入并设置时间 * diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/WebSocketServiceImpl.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/WebSocketServiceImpl.java index 04efa6d3..006cfc07 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/WebSocketServiceImpl.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/WebSocketServiceImpl.java @@ -5,8 +5,12 @@ import cn.hutool.json.JSONUtil; import com.abin.mallchat.common.common.annotation.FrequencyControl; import com.abin.mallchat.common.common.config.ThreadPoolConfig; +import com.abin.mallchat.common.common.constant.RedisKey; import com.abin.mallchat.common.common.event.UserOfflineEvent; import com.abin.mallchat.common.common.event.UserOnlineEvent; +import com.abin.mallchat.common.common.exception.BusinessException; +import com.abin.mallchat.common.common.exception.CommonErrorEnum; +import com.abin.mallchat.common.common.utils.RedisUtils; import com.abin.mallchat.common.user.dao.UserDao; import com.abin.mallchat.common.user.domain.entity.User; import com.abin.mallchat.common.user.domain.enums.RoleEnum; @@ -73,6 +77,12 @@ public class WebSocketServiceImpl implements WebSocketService { */ private static final ConcurrentHashMap> ONLINE_UID_MAP = new ConcurrentHashMap<>(); + /** + * 微信二维码code过期时间 + */ + private static final Duration CODE_EXPIRE_TIME = Duration.ofHours(1); + + public static ConcurrentHashMap getOnlineMap() { return ONLINE_WS_MAP; } @@ -102,8 +112,8 @@ public static ConcurrentHashMap getOnlineMap() { @Override @FrequencyControl(time = 100, count = 5, spEl = "T(com.abin.mallchat.common.common.utils.RequestHolder).get().getIp()") public void handleLoginReq(Channel channel) { - //生成随机不重复的登录码 - Integer code = generateLoginCode(channel); + //通过redis生成随机不重复的登录码 + Integer code = generateLoginCodeByRedis(channel); //请求微信接口,获取登录码地址 WxMpQrCodeTicket wxMpQrCodeTicket = wxMpService.getQrcodeService().qrCodeCreateTmpTicket(code, (int) EXPIRE_TIME.getSeconds()); //返回给前端 @@ -124,6 +134,22 @@ private Integer generateLoginCode(Channel channel) { return CODE.get(); } + /** + * 通过redis原子自增操作获取code,获取后将code放入到redis的kv中,同时设置过期时间 + * @param channel + * @return + */ + private Integer generateLoginCodeByRedis(Channel channel) { + Long code = RedisUtils.inc(RedisKey.WX_RANDOM_CODE_STRING); + if (code > Integer.MAX_VALUE) { + RedisUtils.reset(RedisKey.WX_RANDOM_CODE_STRING); + } + if (!RedisUtils.setnx(String.valueOf(code), channel, CODE_EXPIRE_TIME.getSeconds())) { + throw new BusinessException(CommonErrorEnum.SYSTEM_ERROR); + } + return code.intValue(); + } + /** * 处理所有ws连接的事件 * @@ -208,12 +234,12 @@ private boolean offline(Channel channel, Optional uidOptional) { @Override public Boolean scanLoginSuccess(Integer loginCode, User user, String token) { //发送消息 - Channel channel = WAIT_LOGIN_MAP.getIfPresent(loginCode); + Channel channel = RedisUtils.get(String.valueOf(loginCode), Channel.class); if (Objects.isNull(channel)) { return Boolean.FALSE; } //移除code - WAIT_LOGIN_MAP.invalidate(loginCode); + RedisUtils.del(String.valueOf(loginCode)); //用户登录 loginSuccess(channel, user, token); return true; @@ -221,7 +247,7 @@ public Boolean scanLoginSuccess(Integer loginCode, User user, String token) { @Override public Boolean scanSuccess(Integer loginCode) { - Channel channel = WAIT_LOGIN_MAP.getIfPresent(loginCode); + Channel channel = RedisUtils.get(String.valueOf(loginCode), Channel.class); if (Objects.isNull(channel)) { return Boolean.FALSE; }