Spring Boot 整合 SSE(Server-Sent Events)

1、简述

SSE(Server-Sent Events)是一种基于HTTP协议的单向通信机制,允许服务器向浏览器持续发送实时更新。与WebSocket不同,SSE更简单,使用HTTP/1.1协议即可,不需要额外的协议升级。

SSE的特点:

  • 单向通信:服务器推送数据给客户端,客户端无法向服务器发送消息。

  • 简单易用:基于HTTP协议,无需复杂的配置。

  • 浏览器支持:现代浏览器大多内置支持(如Chrome、Edge、Firefox等)。

2、Spring Boot 中的SSE实现

2.1 添加依赖

SSE无需额外的依赖,Spring Boot自带对SSE的支持。创建一个Spring Boot项目即可。

java 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2.2 实现后端接口

使用MediaType.TEXT_EVENT_STREAM_VALUE作为返回类型即可开启SSE。以下代码是一个简单的实现。

java 复制代码
package com.example.sse.controller;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalTime;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

@RestController
public class SseController {

    @GetMapping(value = "/sse/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Stream<String> stream() {
        // 模拟数据流
        return Stream.generate(() -> "当前时间:" + LocalTime.now())
                     .limit(10); // 限制10条消息
    }
}

2.3 配置超时时间(可选)

默认情况下,Spring Boot的响应会超时。可以在application.properties中调整超时时间:

java 复制代码
server.servlet.session.timeout=30s
spring.mvc.async.request-timeout=30000

2.4 前端实现

SSE在前端通过EventSource对象实现。以下是一个简单的前端示例:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SSE Example</title>
</head>
<body>
    <h1>实时消息</h1>
    <div id="messages"></div>

    <script>
        const eventSource = new EventSource('/sse/stream');

        eventSource.onmessage = function(event) {
            const messagesDiv = document.getElementById('messages');
            const newMessage = document.createElement('p');
            newMessage.textContent = event.data;
            messagesDiv.appendChild(newMessage);
        };

        eventSource.onerror = function() {
            console.error('SSE连接出错,正在尝试重连...');
            eventSource.close();
        };
    </script>
</body>
</html>

3、高级实践

使用Spring Scheduler推送数据,在实际场景中,可能需要定时向客户端推送数据。例如,监控系统定时更新。

java 复制代码
package com.example.sse.service;

import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.concurrent.CopyOnWriteArrayList;

@Service
public class SsePushService {

    private final CopyOnWriteArrayList<SseEmitter> emitters = new CopyOnWriteArrayList<>();

    public SseEmitter subscribe() {
        SseEmitter emitter = new SseEmitter(30_000L);
        emitters.add(emitter);
        emitter.onCompletion(() -> emitters.remove(emitter));
        emitter.onTimeout(() -> emitters.remove(emitter));
        return emitter;
    }

    public void pushMessage(String message) {
        for (SseEmitter emitter : emitters) {
            try {
                emitter.send(message, MediaType.TEXT_PLAIN);
            } catch (IOException e) {
                emitters.remove(emitter);
            }
        }
    }
}

创建一个控制器订阅和推送消息:

java 复制代码
package com.example.sse.controller;

import com.example.sse.service.SsePushService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SsePushController {

    private final SsePushService ssePushService;

    public SsePushController(SsePushService ssePushService) {
        this.ssePushService = ssePushService;
    }

    @GetMapping("/sse/subscribe")
    public SseEmitter subscribe() {
        return ssePushService.subscribe();
    }

    @GetMapping("/sse/push")
    public void pushMessage() {
        ssePushService.pushMessage("当前时间:" + System.currentTimeMillis());
    }
}

注意事项:

  • 浏览器兼容性:SSE不支持IE,但现代浏览器支持良好。

  • 连接断开处理:可通过EventSourceonerror事件重新连接。

  • 性能问题:对大量订阅者时,需考虑使用分布式消息队列优化(如Kafka)。

  • 超时时间:默认30秒超时,需要根据实际需求调整。

4、适用场景

  • 实时通知:如监控系统的告警推送。

  • 实时更新:如股票行情、体育比分。

  • 消息流:如系统日志、任务进度。

相关推荐
悟空码字14 小时前
Spring Boot 整合 MongoDB 最佳实践:CRUD、分页、事务、索引全覆盖
java·spring boot·后端
皮皮林5512 天前
拒绝写重复代码,试试这套开源的 SpringBoot 组件,效率翻倍~
java·spring boot
用户908324602735 天前
Spring AI 1.1.2 + Neo4j:用知识图谱增强 RAG 检索(上篇:图谱构建)
java·spring boot
用户8307196840825 天前
Spring Boot 集成 RabbitMQ :8 个最佳实践,杜绝消息丢失与队列阻塞
spring boot·后端·rabbitmq
Java水解6 天前
Spring Boot 视图层与模板引擎
spring boot·后端
Java水解6 天前
一文搞懂 Spring Boot 默认数据库连接池 HikariCP
spring boot·后端
洋洋技术笔记6 天前
Spring Boot Web MVC配置详解
spring boot·后端
初次攀爬者6 天前
Kafka 基础介绍
spring boot·kafka·消息队列
用户8307196840826 天前
spring ai alibaba + nacos +mcp 实现mcp服务负载均衡调用实战
spring boot·spring·mcp
Java水解7 天前
SpringBoot3全栈开发实战:从入门到精通的完整指南
spring boot·后端