document.write("");

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>

  

posted @ 2025-10-11 16:51  人间春风意  阅读(3)  评论(0)    收藏  举报