From 024a0d6b70b625396b2f4e04b2b346a686e312ba Mon Sep 17 00:00:00 2001 From: lilinxiang <970259858@qq.com> Date: Wed, 15 Oct 2025 11:07:39 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E4=BC=98=E5=8C=96=20sse=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E7=9B=B8=E5=90=8Ctoken=E5=8E=86=E5=8F=B2=E8=BF=9E?= =?UTF-8?q?=E6=8E=A5=E6=9C=AA=E5=85=B3=E9=97=AD=E9=97=AE=E9=A2=98=EF=BC=9B?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=BF=83=E8=B7=B3=E7=9B=91=E6=B5=8B=EF=BC=8C?= =?UTF-8?q?=E5=85=B3=E9=97=AD=E6=97=A0=E6=95=88=E8=BF=9E=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sse/config/SseAutoConfiguration.java | 2 ++ .../common/sse/core/SseEmitterManager.java | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseAutoConfiguration.java b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseAutoConfiguration.java index 0cf8054ed..3b5e8692e 100644 --- a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseAutoConfiguration.java +++ b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseAutoConfiguration.java @@ -7,6 +7,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; +import org.springframework.scheduling.annotation.EnableScheduling; /** * SSE 自动装配 @@ -16,6 +17,7 @@ import org.springframework.context.annotation.Bean; @AutoConfiguration @ConditionalOnProperty(value = "sse.enabled", havingValue = "true") @EnableConfigurationProperties(SseProperties.class) +@EnableScheduling public class SseAutoConfiguration { @Bean diff --git a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java index bc19460f8..b6a4a6dfc 100644 --- a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java +++ b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java @@ -4,6 +4,7 @@ import cn.hutool.core.map.MapUtil; import lombok.extern.slf4j.Slf4j; import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.sse.dto.SseMessageDto; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.io.IOException; @@ -38,6 +39,12 @@ public class SseEmitterManager { // 每个用户可以有多个 SSE 连接,通过 token 进行区分 Map emitters = USER_TOKEN_EMITTERS.computeIfAbsent(userId, k -> new ConcurrentHashMap<>()); + // 关闭已存在的SseEmitter,防止超过最大连接数 + SseEmitter oldEmitter = emitters.remove(token); + if (oldEmitter != null) { + oldEmitter.complete(); + } + // 创建一个新的 SseEmitter 实例,超时时间设置为一天 避免连接之后直接关闭浏览器导致连接停滞 SseEmitter emitter = new SseEmitter(86400000L); @@ -97,6 +104,30 @@ public class SseEmitterManager { } } + /** + * SSE心跳监测,关闭无效连接 + */ + @Scheduled(fixedRate = 60000L) // 每分钟执行一次 + public void sseMonitor() { + for (Map.Entry> userEmitters : USER_TOKEN_EMITTERS.entrySet()) { + Map emitters = userEmitters.getValue(); + if (MapUtil.isNotEmpty(emitters)) { + for (Map.Entry entry : emitters.entrySet()) { + try { + // 向客户端发送心跳 + entry.getValue().send(SseEmitter.event().comment("heartbeat")); + } catch (Exception e) { + log.warn("心跳发送失败, 关闭连接: userId={}, token={}", userEmitters.getKey(), entry.getKey()); + SseEmitter remove = emitters.remove(entry.getKey()); + if (remove != null) { + remove.complete(); + } + } + } + } + } + } + /** * 订阅SSE消息主题,并提供一个消费者函数来处理接收到的消息 *