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

SSE 技术简介

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

Spring Boot 集成 SSE

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

1. 添加依赖

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

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

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

java 复制代码
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 页面来接收服务器推送的消息:

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 功能,实现服务器向客户端的实时数据推送。

相关推荐
李梨同学丶14 分钟前
0201好虫子周刊
后端
思想在飞肢体在追24 分钟前
Springboot项目配置Nacos
java·spring boot·后端·nacos
cyforkk26 分钟前
09、Java 基础硬核复习:异常处理(容错机制)的核心逻辑与面试考点
java·数据库·面试
??(lxy)1 小时前
java高性能无锁队列——MpscLinkedQueue
java·开发语言
数研小生1 小时前
Full Analysis of Taobao Item Detail API taobao.item.get
java·服务器·前端
Wang15301 小时前
Java编程基础与面向对象核心概念
java
毕设源码-郭学长1 小时前
【开题答辩全过程】以 康复管理系统为例,包含答辩的问题和答案
java
毅炼1 小时前
hot100打卡——day17
java·数据结构·算法·leetcode·深度优先
winfreedoms1 小时前
java-网络编程——黑马程序员学习笔记
java·网络·学习
开开心心就好2 小时前
键盘改键工具免安装,自定义键位屏蔽误触
java·网络·windows·随机森林·计算机外设·电脑·excel