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 34aecbd4..edf4a2b3 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 @@ -7,4 +7,6 @@ public interface UserTokenConstant { Integer KICK_CODE = 10000; + Integer KEEPALIVE_CODE = 10001; + } 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 b485deaa..3be40b09 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 @@ -13,10 +13,14 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import javax.websocket.*; + import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.io.IOException; +import java.util.Map; +import java.util.Set; @Slf4j @Component @@ -37,7 +41,7 @@ public class UserResourceCheck { } @Lock4j(name = "achieveDiagnoseResourceAndOpenConnection") - public void achieveDiagnoseResourceAndOpenConnection(String uid, Session session){ + public void achieveDiagnoseResourceAndOpenConnection(String uid, Session session) { // 如果小于数字人最大连接数,则可以连接 if (!achieveDiagnoseResource()) { throw new BusinessException("暂时没有资源,建立连接失败"); @@ -46,21 +50,52 @@ public class UserResourceCheck { // 链接之前先把之前的用户踢下线(ignoreSessionId防止把当前用户踢下线) // 注意,这里如果用户没有进到问诊页面,只是在问诊大厅时,是不会被踢掉的.(因为这时没有建立websocket连接,还没与放到SESSION_POOL里面去) redisTemplate.convertAndSend(UserTokenConstant.KICK_CHANNEL, JSONUtil.toJsonStr(new UserWebSocketDTO(uid, session.getId()))); - log.info("尝试踢该用户{}的其他session下线,忽略sessionId:{}",uid,session.getId()); + log.info("尝试踢该用户{}的其他session下线,忽略sessionId:{}", uid, session.getId()); redisTemplate.opsForHash().put(UserTokenConstant.USER_WEBSOCKET_CACHE, uid, session.getId()); } + /** + * websocket保活接口 + */ + @Scheduled(fixedDelay = 5 * 1000L) + public void keepalive() { + for (Map.Entry entries : WebSocketServer.SESSION_POOL.entrySet()) { + String userId = entries.getKey(); + Session session = entries.getValue(); + if (ObjectUtil.isNotEmpty(session)) { + try { + session.getBasicRemote().sendText(JSONUtil.toJsonStr(new Keepalive())); + } catch (IOException e) { + log.error("用户:{}的websocket连接异常", e.getMessage()); + // 连接异常的用户,移除 + WebSocketServer.SESSION_POOL.remove(userId); + // 移除redis中该用户的缓存 + redisTemplate.opsForHash().delete(UserTokenConstant.USER_WEBSOCKET_CACHE, userId); + } + } + } + + } + // 实现一个方法用于踢下线用户,走的是Redis的消息队列 - public void kickUser(String userId, String ignoreSessionId) throws IOException { + public void kickUser(String userId, String ignoreSessionId) { log.info("尝试踢用户:{}下线", userId); Session session = WebSocketServer.SESSION_POOL.get(userId); // 只有不是忽略剔除的sessionId才可以踢下线 if (ObjectUtil.isNotEmpty(session) && !StrUtil.equals(ignoreSessionId, session.getId())) { - session.getBasicRemote().sendText(JSONUtil.toJsonStr(new Kick())); - session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "用户被踢下线")); - WebSocketServer.SESSION_POOL.remove(userId); - log.info("踢用户:{},sessionId:{} 下线成功", userId, session.getId()); - return; + try { + session.getBasicRemote().sendText(JSONUtil.toJsonStr(new Kick())); + session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "用户被踢下线")); + WebSocketServer.SESSION_POOL.remove(userId); + log.info("踢用户:{},sessionId:{} 下线成功", userId, session.getId()); + return; + } catch (IOException e) { + log.error("用户:{}的websocket连接异常", e.getMessage()); + // 连接异常的用户,移除 + WebSocketServer.SESSION_POOL.remove(userId); + // 移除redis中该用户的缓存 + redisTemplate.opsForHash().delete(UserTokenConstant.USER_WEBSOCKET_CACHE, userId); + } } log.info("踢用户:{}下线,未找到用户,踢下线失败", userId); } @@ -73,4 +108,12 @@ public class UserResourceCheck { } + @Data + public static class Keepalive { + private final Integer code = UserTokenConstant.KEEPALIVE_CODE; + + private final String message = "keepalive"; + + } + }