SSE 接口示例
import org.springframework.http.MediaType; 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; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; @RestController public class SseController { // 创建一个线程池用于异步发送消息 private final ExecutorService executor = Executors.newFixedThreadPool(10); /* * SSE 接口示例 * */ @GetMapping(value = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public SseEmitter sse() { SseEmitter emitter = new SseEmitter(Long.MAX_VALUE); // 默认超时时间为30秒,这里设定为永不超时 // 用于标记任务是否已完成 AtomicBoolean isCompleted = new AtomicBoolean(false); // 添加完成回调,确保任务在连接断开时能正确终止 emitter.onCompletion(() -> { System.out.println("SSE连接已完成"); if (isCompleted.compareAndSet(false, true)) { System.out.println("SSE消息发送任务已完全结束"); // 可以在这里添加其他结束后的处理逻辑 // 例如:记录日志、清理资源、通知其他服务等 } }); emitter.onTimeout(() -> { System.out.println("SSE连接超时"); if (isCompleted.compareAndSet(false, true)) { System.out.println("SSE消息发送任务因超时而结束"); } // 不主动调用complete(),保持连接 }); emitter.onError((error) -> { System.out.println("SSE连接发生错误: " + error.getMessage()); if (isCompleted.compareAndSet(false, true)) { System.out.println("SSE消息发送任务因错误而结束"); } // 不主动调用completeWithError(),保持连接 }); executor.execute(() -> { try { String planSendMessage = "欢迎访问xxx系统,X一对一助手已上线!"; for (int i = 0; i < planSendMessage.length(); i++) { // 检查连接是否仍然有效后再发送 if (!isCompleted.get()) { emitter.send(SseEmitter.event().name("message").data(planSendMessage.charAt(i))); Thread.sleep(100); // 每100毫秒发送一次 } else { break; } } // 发送完成后发送结束标识,但不关闭连接 if (!isCompleted.get()) { emitter.send(SseEmitter.event().name("end").data("END")); System.out.println("消息发送完成,但连接保持开启"); } } catch (IOException | InterruptedException e) { System.err.println("发送过程中发生异常: " + e.getMessage()); // 即使发生异常也不关闭连接 } }); return emitter; } }
<!DOCTYPE html> <html> <head> <title>SSE 示例</title> </head> <body> <h1>Server-Sent Events 测试</h1> <div id="output"></div> <script> const eventSource = new EventSource('http://10.5.44.70:10005/sse'); eventSource.onmessage = function (event) { // 在同一行追加显示,使用span元素分隔 let message = event.data; if (message.startsWith('"') && message.endsWith('"')) { message = message.substring(1, message.length - 1); } // 在同一行追加显示 if (output.innerHTML.length > 0) { output.innerHTML += ' ' + message; } else { output.innerHTML = message; } // 如果内容过长,自动滚动到右侧 output.scrollLeft = output.scrollWidth; }; eventSource.addEventListener('message', function (event) { console.log('收到消息:', event.data); }); eventSource.onerror = function (err) { console.error("EventSource failed:", err); }; </script> </body> </html>