From 0fbb59b18ee7a1d2362dde49d908fb6c8f9eb0fa Mon Sep 17 00:00:00 2001 From: Ziin Date: Fri, 18 Jul 2025 19:04:33 +0800 Subject: [PATCH] =?UTF-8?q?1.=E5=88=A0=E9=99=A4=E6=97=A0=E7=94=A8=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=202.Sse=20=E6=B7=BB=E5=8A=A0=E5=BF=83=E8=B7=B3?= =?UTF-8?q?=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../springbootinit/utils/SseEmitterUtil.java | 27 ++++++++++++++++--- src/main/resources/application.yml | 18 ------------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/yupi/springbootinit/utils/SseEmitterUtil.java b/src/main/java/com/yupi/springbootinit/utils/SseEmitterUtil.java index 84d8dc8..4d7ac54 100644 --- a/src/main/java/com/yupi/springbootinit/utils/SseEmitterUtil.java +++ b/src/main/java/com/yupi/springbootinit/utils/SseEmitterUtil.java @@ -8,7 +8,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.*; import java.util.function.Consumer; /** @@ -16,7 +16,8 @@ import java.util.function.Consumer; */ @Slf4j public class SseEmitterUtil { - + + private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); /** * 使用map对象,便于根据userId来获取对应的SseEmitter,或者放redis里面 */ @@ -25,16 +26,30 @@ public class SseEmitterUtil { public static SseEmitter connect(String userId) { // 设置超时时间,0表示不过期。默认30S,超时时间未完成会抛出异常:AsyncRequestTimeoutException SseEmitter sseEmitter = new SseEmitter(0L); - + + // 设置超时时间为0表示永不超时,或设置为较长的时间 + // 注册回调 sseEmitter.onCompletion(completionCallBack(userId)); sseEmitter.onError(errorCallBack(userId)); sseEmitter.onTimeout(timeoutCallBack(userId)); sseEmitterMap.put(userId, sseEmitter); - log.info("创建新的 SSE 连接,当前用户 {}, 连接总数 {}", userId, sseEmitterMap.size()); + // 启动一个任务定期发送心跳 + ScheduledFuture heartbeat = scheduler.scheduleAtFixedRate(() -> { + try { + // 发送心跳注释,防止代理或浏览器断开 + sseEmitter.send(SseEmitter.event().comment("heartbeat")); + } catch (IOException e) { + sseEmitter.completeWithError(e); + } + }, 0, 10, TimeUnit.SECONDS); // 每10秒一次 + return sseEmitter; } + + + /** * 给制定用户发送消息 @@ -113,6 +128,10 @@ public class SseEmitterUtil { public static SseEmitter getSseEmitter(String userId) { return sseEmitterMap.get(userId); } + + + + private static Runnable completionCallBack(String userId) { return () -> { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index bc5bf4f..b4ff465 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -83,24 +83,6 @@ knife4j: api-rule-resources: - com.yupi.springbootinit.controller -############## Sa-Token 配置 (文档: https://sa-token.cc) ############## -sa-token: - # token 名称(同时也是 cookie 名称) - token-name: vvtoken - # token 有效期(单位:秒) 默认30天,-1 代表永久有效 - timeout: 2592000 - # token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结 - active-timeout: -1 - # 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录) - is-concurrent: false - # 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token) - is-share: false - # token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik) - token-style: random-128 - # 是否输出操作日志 - is-log: true - - logging: level: org.mybatis: off