From 47e586e7f5859f4cf14dcc51ca670a615fc15a19 Mon Sep 17 00:00:00 2001 From: Azure <983547216@qq.com> Date: Tue, 23 Jun 2026 12:53:01 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20satoken=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/config/SaTokenConfigure.java | 3 ++- .../handler/GlobalExceptionHandler.java | 11 ++++++++ .../webgamebackend/ws/RoomSessionManager.java | 25 ++++++++++++++++++- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/webgame/webgamebackend/common/config/SaTokenConfigure.java b/src/main/java/com/webgame/webgamebackend/common/config/SaTokenConfigure.java index d7b5bd6..5e51ab9 100644 --- a/src/main/java/com/webgame/webgamebackend/common/config/SaTokenConfigure.java +++ b/src/main/java/com/webgame/webgamebackend/common/config/SaTokenConfigure.java @@ -27,9 +27,10 @@ public class SaTokenConfigure implements WebMvcConfigurer { .notMatch("/v3/api-docs/**") .notMatch("/webjars/**") .notMatch("/error") + .notMatch("/sse/**") .check(r -> StpUtil.checkLogin()); })).addPathPatterns("/**") - .excludePathPatterns("/error"); + .excludePathPatterns("/error", "/sse/**"); } /** diff --git a/src/main/java/com/webgame/webgamebackend/common/handler/GlobalExceptionHandler.java b/src/main/java/com/webgame/webgamebackend/common/handler/GlobalExceptionHandler.java index d3295bc..ccd0f05 100644 --- a/src/main/java/com/webgame/webgamebackend/common/handler/GlobalExceptionHandler.java +++ b/src/main/java/com/webgame/webgamebackend/common/handler/GlobalExceptionHandler.java @@ -3,6 +3,7 @@ package com.webgame.webgamebackend.common.handler; import cn.dev33.satoken.exception.NotLoginException; import cn.dev33.satoken.exception.NotPermissionException; import cn.dev33.satoken.exception.NotRoleException; +import cn.dev33.satoken.exception.SaTokenContextException; import com.webgame.webgamebackend.common.dto.ApiResponse; import com.webgame.webgamebackend.common.exception.BusinessException; import com.webgame.webgamebackend.common.exception.ErrorCode; @@ -38,6 +39,16 @@ public class GlobalExceptionHandler { // SSE 长连接超时是正常行为,无需记录日志 } + /** + * SaToken 上下文未初始化(异步分派时线程局部变量丢失) + * + * 返回 void 避免 Spring 尝试以 JSON 写入已提交的 text/event-stream 响应导致二次异常。 + */ + @ExceptionHandler(SaTokenContextException.class) + public void handleSaTokenContext(SaTokenContextException ex) { + log.warn("SaToken 上下文未初始化(异步分派场景): {}", ex.getMessage()); + } + // ==================== 业务异常 ==================== /** diff --git a/src/main/java/com/webgame/webgamebackend/ws/RoomSessionManager.java b/src/main/java/com/webgame/webgamebackend/ws/RoomSessionManager.java index 73296f8..73bbc72 100644 --- a/src/main/java/com/webgame/webgamebackend/ws/RoomSessionManager.java +++ b/src/main/java/com/webgame/webgamebackend/ws/RoomSessionManager.java @@ -30,16 +30,39 @@ public class RoomSessionManager { /** * 将用户会话加入指定房间 * + * 如果同一用户在此房间已有旧会话(重连场景),先关闭旧会话再注册新的。 + * * @param roomId 房间 ID * @param userId 用户 ID * @param session WebSocket 会话 */ public void addSession(String roomId, String userId, WebSocketSession session) { + // 清理同一用户在此房间的旧会话(重连场景) + Set sessions = roomSessions.get(roomId); + if (sessions != null) { + for (WebSocketSession existing : sessions) { + if (userId.equals(sessionUsers.get(existing.getId()))) { + // 关闭旧连接(静默关闭,不触发 leave 逻辑) + try { + existing.close(); + } catch (Exception ignored) { + } + sessions.remove(existing); + sessionUsers.remove(existing.getId()); + sessionRooms.remove(existing.getId()); + log.info("[WS会话] 清理旧会话, roomId={}, userId={}, oldSessionId={}", + roomId, userId, existing.getId()); + break; + } + } + } + roomSessions.computeIfAbsent(roomId, k -> ConcurrentHashMap.newKeySet()).add(session); sessionUsers.put(session.getId(), userId); sessionRooms.put(session.getId(), roomId); log.info("[WS会话] 加入房间, roomId={}, userId={}, sessionId={}, 当前房间连接数={}", - roomId, userId, session.getId(), roomSessions.get(roomId).size()); + roomId, userId, session.getId(), + roomSessions.get(roomId) != null ? roomSessions.get(roomId).size() : 0); } /**