From 25450fc781d2a24d07155237e54fb2e3d211eca8 Mon Sep 17 00:00:00 2001 From: liu Date: Tue, 5 Dec 2023 16:37:30 +0800 Subject: [PATCH] =?UTF-8?q?=E9=97=AE=E8=AF=8A=E5=A4=A7=E5=8E=85=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../supervision/config/JwtInterceptor.java | 21 ---------------- .../constant/UserTokenConstant.java | 3 --- .../controller/UserController.java | 10 -------- .../controller/WebSocketServer.java | 25 ++++++++++++------- .../service/impl/DiagnoseHallServiceImpl.java | 5 +--- .../usermanage/KickUserListener.java | 8 +++--- .../usermanage/UserWebSocketDTO.java | 16 ++++++++++++ 7 files changed, 38 insertions(+), 50 deletions(-) create mode 100644 virtual-patient-web/src/main/java/com/supervision/usermanage/UserWebSocketDTO.java diff --git a/virtual-patient-common/src/main/java/com/supervision/config/JwtInterceptor.java b/virtual-patient-common/src/main/java/com/supervision/config/JwtInterceptor.java index 8513504d..6dfb5735 100644 --- a/virtual-patient-common/src/main/java/com/supervision/config/JwtInterceptor.java +++ b/virtual-patient-common/src/main/java/com/supervision/config/JwtInterceptor.java @@ -58,27 +58,6 @@ public class JwtInterceptor implements HandlerInterceptor { return true; } - public void checkSingleLogin(String userId, JWT currentJwt) { - - if (Boolean.FALSE.equals(redisTemplate.hasKey(UserTokenConstant.TOKEN_CACHE + userId))) { - throw new BusinessException("用户已被踢下线或超时,请重新登录", 505); - } - String value = redisTemplate.opsForValue().get(UserTokenConstant.TOKEN_CACHE + userId); - - long redisCacheTime = Long.parseLong(String.valueOf(value)); - Object currentJwtIssueTimeObject = currentJwt.getPayload("issueTime"); - long currentJwtIssueTime = Long.parseLong(String.valueOf(currentJwtIssueTimeObject)); - if (redisCacheTime == currentJwtIssueTime) { - // 如果相等,说明这个token就是最新的,直接放行 - return; - } else if (currentJwtIssueTime > redisCacheTime) { - // 如果当前请求时间,大于Redis缓存时间,说明重新登录了,这个时候要把最新的放到缓存中 - redisTemplate.opsForValue().set(UserTokenConstant.TOKEN_CACHE + userId, String.valueOf(System.currentTimeMillis()), 1000 * 5L, TimeUnit.MILLISECONDS); - } else { - // 走到这里,说明redisCacheTime是最新的,说明当前用户请求了一个新的token,那么原来的用户就踢掉 - throw new BusinessException("当前用户已在其他地方登录!", 505); - } - } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, diff --git a/virtual-patient-common/src/main/java/com/supervision/constant/UserTokenConstant.java b/virtual-patient-common/src/main/java/com/supervision/constant/UserTokenConstant.java index 29466321..2e1d4769 100644 --- a/virtual-patient-common/src/main/java/com/supervision/constant/UserTokenConstant.java +++ b/virtual-patient-common/src/main/java/com/supervision/constant/UserTokenConstant.java @@ -1,9 +1,6 @@ package com.supervision.constant; public interface UserTokenConstant { - - String TOKEN_CACHE = "USER:LOGIN:TOKEN:"; - String USER_ID_CACHE = "USER:ID:CACHE"; String KICK_CHANNEL = "USER:KICK:CHANNEL"; diff --git a/virtual-patient-web/src/main/java/com/supervision/controller/UserController.java b/virtual-patient-web/src/main/java/com/supervision/controller/UserController.java index 0af12668..c692e824 100644 --- a/virtual-patient-web/src/main/java/com/supervision/controller/UserController.java +++ b/virtual-patient-web/src/main/java/com/supervision/controller/UserController.java @@ -43,19 +43,9 @@ public class UserController { throw new BusinessException("密码错误"); } String token = TokenUtil.creatToken(JSONUtil.toJsonStr(user.get())); - // 将用户的token保存起来,超时时间为5分钟 - redisTemplate.opsForValue().set(UserTokenConstant.TOKEN_CACHE + user.get().getId(), String.valueOf(System.currentTimeMillis()), 1000 * 5L, TimeUnit.MILLISECONDS); return token; } - @ApiOperation("token心跳") - @PostMapping("keepaliveToken") - public void keepaliveToken() { - User user = UserUtil.getUser(); - // 每次心跳都设置为5分钟之后 - redisTemplate.expire(UserTokenConstant.TOKEN_CACHE + user.getId(), 1000 * 5L, TimeUnit.MILLISECONDS); - } - @ApiOperation("踢用户下线") @GetMapping("kickUser") public void kickUser(String userId) { diff --git a/virtual-patient-web/src/main/java/com/supervision/controller/WebSocketServer.java b/virtual-patient-web/src/main/java/com/supervision/controller/WebSocketServer.java index 1a122a26..05b1b078 100644 --- a/virtual-patient-web/src/main/java/com/supervision/controller/WebSocketServer.java +++ b/virtual-patient-web/src/main/java/com/supervision/controller/WebSocketServer.java @@ -1,7 +1,10 @@ package com.supervision.controller; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; import com.supervision.constant.UserTokenConstant; +import com.supervision.usermanage.UserWebSocketDTO; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -29,10 +32,12 @@ public class WebSocketServer { * 有客户端连接成功 */ @OnOpen - public void onOpen(Session session, @PathParam(value = "uid") String uid) { + public void onOpen(Session session, @PathParam(value = "uid") String uid) throws IOException { log.info("用户:{}登录,缓存到Redis", uid); + // 链接之前先把之前的用户踢下线(ignoreSessionId防止把当前用户踢下线) + redisTemplate.convertAndSend(UserTokenConstant.KICK_CHANNEL, JSONUtil.toJsonStr(new UserWebSocketDTO(uid, session.getId()))); SESSION_POOL.put(uid, session); - redisTemplate.opsForSet().add(UserTokenConstant.USER_ID_CACHE, uid); + redisTemplate.opsForHash().put(UserTokenConstant.USER_ID_CACHE, uid, session.getId()); } /** @@ -40,9 +45,9 @@ public class WebSocketServer { */ @OnClose public void onClose(Session session, @PathParam(value = "uid") String uid) { - redisTemplate.opsForSet().remove(UserTokenConstant.USER_ID_CACHE, uid); + redisTemplate.opsForHash().delete(UserTokenConstant.USER_ID_CACHE, uid, session.getId()); SESSION_POOL.remove(uid); - log.info("用户:{}关闭,从Redis中移除,当前连接数为:{}", uid, redisTemplate.opsForSet().size(UserTokenConstant.USER_ID_CACHE)); + log.info("用户:{}关闭,从Redis中移除,当前连接数为:{}", uid, redisTemplate.opsForHash().size(UserTokenConstant.USER_ID_CACHE)); } /** @@ -50,18 +55,20 @@ public class WebSocketServer { */ @OnError public void onError(Session session, @PathParam(value = "uid") String uid, Throwable throwable) { - redisTemplate.opsForSet().remove(UserTokenConstant.USER_ID_CACHE, uid); + redisTemplate.opsForHash().delete(UserTokenConstant.USER_ID_CACHE, uid, session.getId()); SESSION_POOL.remove(uid); - log.error("用户:{}发生错误,从Redis中移除,当前连接数为:{}", uid, redisTemplate.opsForSet().size(UserTokenConstant.USER_ID_CACHE), throwable); + log.error("用户:{}发生错误,从Redis中移除,当前连接数为:{}", uid, redisTemplate.opsForHash().size(UserTokenConstant.USER_ID_CACHE), throwable); } // 实现一个方法用于踢下线用户,走的是Redis的消息队列 - public void kickUser(String userId) throws IOException { + public void kickUser(String userId, String ignoreSessionId) throws IOException { log.info("尝试主动踢用户:{}下线", userId); Session session = SESSION_POOL.get(userId); - if (ObjectUtil.isNotEmpty(session)) { + // 只有不是忽略剔除的sessionId才可以踢下线 + if (ObjectUtil.isNotEmpty(session) && !StrUtil.equals(ignoreSessionId, session.getId())) { session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "用户被踢下线")); - log.info("主动踢用户:{}下线成功", userId); + SESSION_POOL.remove(userId); + log.info("主动踢用户:{},sessionId:{} 下线成功", userId, session.getId()); return; } log.info("主动踢用户:{}下线,未找到用户,踢下线失败", userId); diff --git a/virtual-patient-web/src/main/java/com/supervision/service/impl/DiagnoseHallServiceImpl.java b/virtual-patient-web/src/main/java/com/supervision/service/impl/DiagnoseHallServiceImpl.java index 0996558b..586c1eda 100644 --- a/virtual-patient-web/src/main/java/com/supervision/service/impl/DiagnoseHallServiceImpl.java +++ b/virtual-patient-web/src/main/java/com/supervision/service/impl/DiagnoseHallServiceImpl.java @@ -23,11 +23,8 @@ public class DiagnoseHallServiceImpl implements DiagnoseHallService { @Override public boolean achieveDiagnoseResource() { long humanMaxNumber = Long.parseLong(resourceNumber); - Long currentUserNum = redisTemplate.opsForSet().size(UserTokenConstant.USER_ID_CACHE); + long currentUserNum = redisTemplate.opsForHash().size(UserTokenConstant.USER_ID_CACHE); // 如果小于数字人最大连接数,则可以连接 - if (null == currentUserNum){ - return true; - } return currentUserNum <= humanMaxNumber; } } diff --git a/virtual-patient-web/src/main/java/com/supervision/usermanage/KickUserListener.java b/virtual-patient-web/src/main/java/com/supervision/usermanage/KickUserListener.java index b2fc923e..c1311808 100644 --- a/virtual-patient-web/src/main/java/com/supervision/usermanage/KickUserListener.java +++ b/virtual-patient-web/src/main/java/com/supervision/usermanage/KickUserListener.java @@ -1,5 +1,6 @@ package com.supervision.usermanage; +import cn.hutool.json.JSONUtil; import com.supervision.constant.UserTokenConstant; import com.supervision.controller.WebSocketServer; import lombok.extern.slf4j.Slf4j; @@ -20,10 +21,11 @@ public class KickUserListener implements MessageListener { @Override public void onMessage(Message message, byte[] pattern) { - String userId = message.toString(); - log.info("Redis的Channel:{}收到踢用户下线消息:{}", UserTokenConstant.KICK_CHANNEL, userId); + String messageString = message.toString(); + UserWebSocketDTO user = JSONUtil.toBean(messageString, UserWebSocketDTO.class); + log.info("Redis的Channel:{}收到踢用户{}下线消息", UserTokenConstant.KICK_CHANNEL, user.getUserId()); try { - webSocketServer.kickUser(userId); + webSocketServer.kickUser(user.getUserId(), user.getIgnoreSessionId()); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/virtual-patient-web/src/main/java/com/supervision/usermanage/UserWebSocketDTO.java b/virtual-patient-web/src/main/java/com/supervision/usermanage/UserWebSocketDTO.java new file mode 100644 index 00000000..42a50b7a --- /dev/null +++ b/virtual-patient-web/src/main/java/com/supervision/usermanage/UserWebSocketDTO.java @@ -0,0 +1,16 @@ +package com.supervision.usermanage; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class UserWebSocketDTO { + + private String userId; + + /** + * 忽略提除的ID + */ + private String ignoreSessionId; +}