tsurumure 10 сар өмнө
parent
commit
24d201c314

+ 5 - 1
src/main/java/com/backendsys/modules/common/config/security/AnonymousProperties.java

@@ -50,9 +50,13 @@ public class AnonymousProperties implements InitializingBean, ApplicationContext
 
             if (method != null) {
                 Pattern pattern = Pattern.compile("\\{(\\w+) \\[(.+?)\\]}");
-                Matcher matcher = pattern.matcher(info.toString());
+                // 排除 SSE协议接口 多余的字段
+                String infoContent = info.toString().replace(", produces [text/event-stream]", "");
+                Matcher matcher = pattern.matcher(infoContent);
+//                Matcher matcher = pattern.matcher(info.toString());
                 if (matcher.find()) {
                     String url = matcher.group(2);
+                    System.out.println("url: " + url);
                     urls.add(url);
                 }
             }

+ 1 - 0
src/main/java/com/backendsys/modules/common/config/security/SecurityConfig.java

@@ -73,6 +73,7 @@ public class SecurityConfig {
 
         // 使用了 @Anonymous 注解的地址
         String[] anonymousUrls = anonymousProperties.getUrls();
+        // System.out.println("(SecurityConfig) anonymousUrls:");
         // System.out.println(Arrays.toString(anonymousUrls));
 
         // 路径授权

+ 2 - 0
src/main/java/com/backendsys/modules/common/config/security/filter/JwtAuthenticationFilter.java

@@ -74,6 +74,8 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
 
         // 使用了 @Anonymous 注解的地址
         String[] anonymousUrls = anonymousProperties.getUrls();
+        // System.out.println("(JwtAuthenticationFilter) anonymousUrls:");
+        // System.out.println(Arrays.toString(anonymousUrls));
 
         // 在配置文件中的 白名单地址
         String[] whiteUrls = ArrayUtil.addAll(JWT_WHITELIST, STATIC_WHITELIST, anonymousUrls);

+ 52 - 0
src/main/java/com/backendsys/modules/log/controller/LogStreamController.java

@@ -0,0 +1,52 @@
+package com.backendsys.modules.log.controller;
+
+import cn.hutool.core.convert.Convert;
+import com.backendsys.modules.common.config.security.annotations.Anonymous;
+import com.backendsys.modules.log.emitter.LogStreamEmitterManager;
+import com.backendsys.modules.log.utils.LogStreamUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+
+import java.io.IOException;
+
+@RestController
+public class LogStreamController {
+
+    @Autowired
+    private LogStreamUtil logStreamUtil;
+
+    /**
+     * [SSE] 消息监听
+     */
+    @Anonymous
+    @GetMapping(value = "/api/log/stream/watch", produces = "text/event-stream")
+    public SseEmitter stream() {
+        String userId = Convert.toStr(1L);
+        SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);
+        LogStreamEmitterManager manager = LogStreamEmitterManager.getInstance();
+        manager.addEmitter(userId, emitter);
+        try {
+            emitter.send(SseEmitter.event().data("success"));
+        } catch (IOException e) {
+            // 当所有事件发送完毕后,关闭连接
+            // emitter.complete();
+            // emitter.completeWithError(e);
+            manager.emitters.remove(emitter);
+        }
+        return emitter;
+    }
+
+    /**
+     * [SSE] 测试发送
+     */
+    @Anonymous
+    @GetMapping("/api/log/stream/send")
+    public String send() {
+        String message = "{\"message\": \"Hello World\"}";
+        logStreamUtil.send(message);
+        return "success";
+    }
+
+}

+ 35 - 0
src/main/java/com/backendsys/modules/log/emitter/LogStreamEmitterManager.java

@@ -0,0 +1,35 @@
+package com.backendsys.modules.log.emitter;
+
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+public class LogStreamEmitterManager {
+    // 单例实例
+    private static final LogStreamEmitterManager INSTANCE = new LogStreamEmitterManager();
+    // 存储SseEmitter的线程安全列表
+//    public final CopyOnWriteArrayList<Long, SseEmitter> emitters = new CopyOnWriteArrayList<>();
+    public final ConcurrentHashMap<String, SseEmitter> emitters = new ConcurrentHashMap<>();
+
+    // 私有构造函数,防止外部直接实例化
+    private LogStreamEmitterManager() {}
+    // 公共静态方法,获取单例实例
+    public static LogStreamEmitterManager getInstance() {
+        return INSTANCE;
+    }
+    // 公共方法,供外部添加SseEmitter
+    public void addEmitter(String userId, SseEmitter emitter) {
+        this.emitters.put(userId, emitter);
+        emitter.onTimeout(() -> this.emitters.remove(emitter));
+        emitter.onCompletion(() -> this.emitters.remove(emitter));
+    }
+    // 公共方法,供外部移除SseEmitter
+    public SseEmitter getEmitter(String userId) {
+        // 根据用户ID获取 SseEmitter
+        return this.emitters.get(userId);
+    }
+    // 公共方法,供外部移除SseEmitter
+    public void removeEmitter(SseEmitter emitter) {
+        this.emitters.remove(emitter);
+    }
+}

+ 30 - 0
src/main/java/com/backendsys/modules/log/utils/LogStreamUtil.java

@@ -0,0 +1,30 @@
+package com.backendsys.modules.log.utils;
+
+import cn.hutool.core.convert.Convert;
+import com.backendsys.modules.log.emitter.LogStreamEmitterManager;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+
+import java.io.IOException;
+
+@Component
+public class LogStreamUtil {
+
+    // [SSE] 发送消息
+    public void send(String data) {
+
+        Long userId = 1L;
+
+        LogStreamEmitterManager manager = LogStreamEmitterManager.getInstance();
+        SseEmitter emitter = manager.getEmitter(Convert.toStr(userId));
+        if (emitter != null) {
+            try {
+                emitter.send(SseEmitter.event().data(data));
+            } catch (IOException e) {
+                System.out.println(e.getMessage());
+                manager.removeEmitter(emitter);
+            }
+        }
+    }
+
+}