From 3c91a96586072aa97cbdf2116e57d331d6a96b17 Mon Sep 17 00:00:00 2001 From: liu Date: Tue, 19 Dec 2023 10:33:33 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4websocket=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../VirtualPatientApplication.java | 2 ++ .../controller/WebSocketServer.java | 33 ++++++++----------- .../usermanage/KickUserListener.java | 4 +-- .../usermanage/UserResourceCheck.java | 22 ++++++++++++- 4 files changed, 39 insertions(+), 22 deletions(-) diff --git a/virtual-patient-web/src/main/java/com/supervision/VirtualPatientApplication.java b/virtual-patient-web/src/main/java/com/supervision/VirtualPatientApplication.java index 918f89d8..31f4f2c9 100644 --- a/virtual-patient-web/src/main/java/com/supervision/VirtualPatientApplication.java +++ b/virtual-patient-web/src/main/java/com/supervision/VirtualPatientApplication.java @@ -3,6 +3,8 @@ package com.supervision; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScans; import org.springframework.web.socket.config.annotation.EnableWebSocket; @SpringBootApplication 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 0aa39942..8a7e436a 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 @@ -4,6 +4,7 @@ import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.supervision.constant.UserTokenConstant; import com.supervision.usermanage.UserResourceCheck; +import com.supervision.util.SpringBeanUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -21,17 +22,22 @@ import java.util.concurrent.ConcurrentHashMap; @ServerEndpoint("/webSocket/{uid}") public class WebSocketServer { - @Autowired - private RedisTemplate redisTemplate; + private static RedisTemplate redisTemplate ; //concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。 - private static final ConcurrentHashMap SESSION_POOL = new ConcurrentHashMap<>(); + public static final ConcurrentHashMap SESSION_POOL = new ConcurrentHashMap<>(); - @Value("${human.resourceMaxNumber}") - private String resourceNumber; + private static UserResourceCheck userResourceCheck ; @Autowired - private UserResourceCheck userResourceCheck; + public void setUserResourceCheck(UserResourceCheck userResourceCheck) { + WebSocketServer.userResourceCheck = userResourceCheck; + } + + @Autowired + public void setRedisTemplate(RedisTemplate redisTemplate) { + WebSocketServer.redisTemplate = redisTemplate; + } /** * 有客户端连接成功 @@ -40,6 +46,7 @@ public class WebSocketServer { public void onOpen(Session session, @PathParam(value = "uid") String uid) { userResourceCheck.achieveDiagnoseResourceAndOpenConnection(uid, session); SESSION_POOL.put(uid, session); + log.info("用户:{}登录成功", uid); } /** @@ -62,17 +69,5 @@ public class WebSocketServer { log.error("用户:{}发生错误,从Redis中移除,当前连接数为:{}", uid, redisTemplate.opsForHash().size(UserTokenConstant.USER_WEBSOCKET_CACHE), throwable); } - // 实现一个方法用于踢下线用户,走的是Redis的消息队列 - public void kickUser(String userId, String ignoreSessionId) throws IOException { - log.info("尝试主动踢用户:{}下线", userId); - Session session = SESSION_POOL.get(userId); - // 只有不是忽略剔除的sessionId才可以踢下线 - if (ObjectUtil.isNotEmpty(session) && !StrUtil.equals(ignoreSessionId, session.getId())) { - session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "用户被踢下线")); - 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/usermanage/KickUserListener.java b/virtual-patient-web/src/main/java/com/supervision/usermanage/KickUserListener.java index c1311808..99c57aa0 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 @@ -17,7 +17,7 @@ import java.io.IOException; public class KickUserListener implements MessageListener { @Autowired - private WebSocketServer webSocketServer; + private UserResourceCheck userResourceCheck; @Override public void onMessage(Message message, byte[] pattern) { @@ -25,7 +25,7 @@ public class KickUserListener implements MessageListener { UserWebSocketDTO user = JSONUtil.toBean(messageString, UserWebSocketDTO.class); log.info("Redis的Channel:{}收到踢用户{}下线消息", UserTokenConstant.KICK_CHANNEL, user.getUserId()); try { - webSocketServer.kickUser(user.getUserId(), user.getIgnoreSessionId()); + userResourceCheck.kickUser(user.getUserId(), user.getIgnoreSessionId()); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/virtual-patient-web/src/main/java/com/supervision/usermanage/UserResourceCheck.java b/virtual-patient-web/src/main/java/com/supervision/usermanage/UserResourceCheck.java index 4d18a7ea..dfc1a7c9 100644 --- a/virtual-patient-web/src/main/java/com/supervision/usermanage/UserResourceCheck.java +++ b/virtual-patient-web/src/main/java/com/supervision/usermanage/UserResourceCheck.java @@ -1,8 +1,11 @@ package com.supervision.usermanage; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import com.baomidou.lock.annotation.Lock4j; import com.supervision.constant.UserTokenConstant; +import com.supervision.controller.WebSocketServer; import com.supervision.exception.BusinessException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -12,6 +15,8 @@ import javax.websocket.*; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; +import java.io.IOException; + @Slf4j @Component @RequiredArgsConstructor @@ -36,10 +41,25 @@ public class UserResourceCheck { if (!achieveDiagnoseResource()) { throw new BusinessException("暂时没有资源,建立连接失败"); } - log.info("用户:{}登录,缓存到Redis", uid); + log.info("用户:{}开始登录,缓存到Redis,并尝试把该用户已有客户端踢下线", uid); // 链接之前先把之前的用户踢下线(ignoreSessionId防止把当前用户踢下线) // 注意,这里如果用户没有进到问诊页面,只是在问诊大厅时,是不会被踢掉的.(因为这时没有建立websocket连接) redisTemplate.convertAndSend(UserTokenConstant.KICK_CHANNEL, JSONUtil.toJsonStr(new UserWebSocketDTO(uid, session.getId()))); redisTemplate.opsForHash().put(UserTokenConstant.USER_WEBSOCKET_CACHE, uid, session.getId()); } + + // 实现一个方法用于踢下线用户,走的是Redis的消息队列 + public void kickUser(String userId, String ignoreSessionId) throws IOException { + log.info("尝试主动踢用户:{}下线", userId); + Session session = WebSocketServer.SESSION_POOL.get(userId); + // 只有不是忽略剔除的sessionId才可以踢下线 + if (ObjectUtil.isNotEmpty(session) && !StrUtil.equals(ignoreSessionId, session.getId())) { + session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "用户被踢下线")); + WebSocketServer.SESSION_POOL.remove(userId); + log.info("主动踢用户:{},sessionId:{} 下线成功", userId, session.getId()); + return; + } + log.info("主动踢用户:{}下线,未找到用户,踢下线失败", userId); + } + }