Spring Boot 应用中实现基本的 SSE 功能

发布于:2025-05-13 ⋅ 阅读:(12) ⋅ 点赞:(0)

SSE 技术简介

SSE(Server-Sent Events)是一种允许服务器主动向客户端推送数据的技术。它基于 HTTP 长连接,使用简单,特别适合实时数据更新场景,如股票行情、新闻推送等。与 WebSocket 相比,SSE 更轻量级,且只支持服务器到客户端的单向通信。

Spring Boot 集成 SSE

下面我将介绍如何在 Spring Boot 中实现 SSE 功能:

1. 添加依赖

首先在 pom.xml 中添加 Spring Web 依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
2. 创建 SSE 控制器

以下是一个简单的 SSE 控制器示例,它可以定时向客户端推送消息:

package com.example.sse.demo.controller;

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.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@RestController
public class SseController {

    // 创建一个单线程的调度器
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

    @GetMapping(path = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter streamSseMvc() {
        SseEmitter emitter = new SseEmitter(60_000L); // 设置超时时间为60秒

        // 启动定时任务,每秒发送一次消息
        scheduler.scheduleAtFixedRate(() -> {
            try {
                // 发送数据
                emitter.send(SseEmitter.event()
                        .id(String.valueOf(System.currentTimeMillis()))
                        .name("message")
                        .data("Hello, SSE! Time: " + System.currentTimeMillis()));
            } catch (IOException e) {
                // 发生异常时,完成发射器
                emitter.completeWithError(e);
            }
        }, 0, 1, TimeUnit.SECONDS);

        // 设置完成回调
        emitter.onCompletion(() -> System.out.println("SSE connection completed"));
        // 设置超时回调
        emitter.onTimeout(() -> {
            System.out.println("SSE connection timed out");
            emitter.complete();
        });
        // 设置错误回调
        emitter.onError((ex) -> {
            System.out.println("SSE connection error: " + ex.getMessage());
            emitter.completeWithError(ex);
        });

        return emitter;
    }
}
3. 创建客户端页面

创建一个简单的 HTML 页面来接收服务器推送的消息:

<!DOCTYPE html>
<html>
<head>
    <title>SSE Demo</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
        }
        #messages {
            border: 1px solid #ccc;
            padding: 10px;
            margin-top: 10px;
            height: 200px;
            overflow-y: auto;
        }
    </style>
</head>
<body>
    <h1>SSE Demo</h1>
    <button onclick="startSse()">Start SSE</button>
    <button onclick="stopSse()">Stop SSE</button>
    
    <div id="messages"></div>

    <script>
        let eventSource;

        function startSse() {
            // 创建 EventSource 实例连接到服务器
            eventSource = new EventSource('/sse');
            
            // 监听 message 事件
            eventSource.onmessage = function(event) {
                const messagesDiv = document.getElementById('messages');
                const newMessage = document.createElement('div');
                newMessage.textContent = `[${new Date().toLocaleTimeString()}] ${event.data}`;
                messagesDiv.appendChild(newMessage);
            };
            
            // 监听错误事件
            eventSource.onerror = function(error) {
                console.error('EventSource failed:', error);
                const messagesDiv = document.getElementById('messages');
                const errorMessage = document.createElement('div');
                errorMessage.textContent = `Error: ${error}`;
                errorMessage.style.color = 'red';
                messagesDiv.appendChild(errorMessage);
                
                // 关闭连接
                eventSource.close();
            };
        }

        function stopSse() {
            if (eventSource) {
                eventSource.close();
                const messagesDiv = document.getElementById('messages');
                const statusMessage = document.createElement('div');
                statusMessage.textContent = 'Connection closed';
                statusMessage.style.color = 'blue';
                messagesDiv.appendChild(statusMessage);
            }
        }
    </script>
</body>
</html>

运行和测试

  1. 启动 Spring Boot 应用
  2. 访问客户端页面(例如:http://localhost:8080/index.html
  3. 点击 “Start SSE” 按钮开始接收服务器推送的消息
  4. 点击 “Stop SSE” 按钮停止接收消息

关键技术点说明

  1. 服务器端

    • 使用 SseEmitter 处理 SSE 连接
    • 设置适当的超时时间
    • 实现错误处理和连接关闭逻辑
    • 使用 MediaType.TEXT_EVENT_STREAM_VALUE 指定响应类型
  2. 客户端

    • 使用 EventSource 对象连接到 SSE 服务器
    • 监听 message 事件接收服务器推送的数据
    • 监听 error 事件处理连接错误
    • 使用 close() 方法关闭连接

注意事项

  1. 生产环境中应考虑使用连接池和更健壮的错误处理机制
  2. 长时间运行的 SSE 连接可能需要处理网络中断和重连问题
  3. 考虑添加身份验证和授权机制保护 SSE 端点
  4. 对于大量并发连接,应评估服务器性能和资源消耗

通过以上步骤,你可以在 Spring Boot 应用中实现基本的 SSE 功能,实现服务器向客户端的实时数据推送。


网站公告

今日签到

点亮在社区的每一天
去签到