news 2026/7/7 20:29:14

SpringBoot3实战:SSE实时推送

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot3实战:SSE实时推送

前言

在当今互联网软件开发的浪潮中,实时数据交互已成为众多应用不可或缺的特性。对于互联网软件开发人员而言,如何高效地实现数据从后端实时推送到前端,是一个值得深入探讨的问题。今天,我们就来聚焦于在 Spring Boot3 框架下,如何巧妙地实现一个基于 SSE 协议的后端服务,将数据实时推送到前端。

SSE 协议是什么

服务器发送事件(Server-Sent Events ,简称 SSE),在现代 Web 应用程序里正变得越来越炙手可热。它提供了一种轻量级的从服务器推送数据给客户端的方式 ,在监控、实时通知、股票价格更新等诸多场景中有着广泛的应用。

SSE 是一种从服务器向客户端推送数据的技术,属于 HTML5 的一部分。与传统的 HTTP 请求 - 响应模型大不相同,SSE 是单向的,服务器能够持续不断地向客户端发送数据,而客户端通过一次长连接就能持续接收这些更新 。

对比广为人知的 WebSocket,SSE 有着自身独特的特点:

  • 单向通信:SSE 仅允许服务器向客户端推送数据,客户端无法向服务器发送数据。这使得它在一些只需要后端主动推送数据的场景中,显得尤为简洁高效。
  • 基于 HTTP 协议:SSE 建立在 HTTP 协议之上,浏览器原生支持,无需额外的协议处理。这大大降低了开发和部署的复杂度,能够轻松融入现有的 HTTP 生态系统。
  • 自动重连:SSE 支持自动重连,当连接意外断开时,客户端会自动尝试重新连接服务器。这一特性在网络环境不稳定的情况下,能够确保数据推送的连续性,极大提升了用户体验。

Spring Boot3 与 SSE 的融合优势

Spring Boot 3 对响应式编程提供了全面支持,它基于 Project Reactor 实现异步、非阻塞的流式数据处理。而响应式编程与 SSE 可谓是天作之合,因为它允许我们以非阻塞的方式持续推送数据,而不会阻塞服务器的宝贵资源 。

Spring WebFlux 作为 Spring Boot 3 中用于构建响应式应用的核心框架,它能够无缝集成 SSE,为开发者打造简单高效的服务器推送功能。在传统的阻塞式编程模式下,处理长连接(如 SSE)时很可能会占用大量服务器资源。但响应式编程借助非阻塞 I/O 操作,不仅能够高效处理长时间的连接,还能在有新数据产生的瞬间,立即推送给客户端。响应式流(如 Flux )天生就契合这种流式数据推送的场景 。

实战:构建 SSE 服务端推送应用

接下来,我们通过实际步骤来实现一个简单的 SSE 服务端推送应用。

(一)创建 Spring Boot 项目并引入 WebFlux 依赖

首先,创建一个全新的 Spring Boot 3 项目。在项目构建过程中,务必引入
spring-boot-starter-webflux 依赖。如果你使用的是 Maven,可以在 pom.xml 文件中添加如下依赖配置:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency>

若你采用 Gradle 构建项目,则在 build.gradle 文件中加入:

implementation 'org.springframework.boot:spring-boot-starter-webflux'

(二)实现服务端推送 SSE 事件流

在 Spring WebFlux 中,SSE 通过返回 Flux<ServerSentEvent<T>> 这种响应流来达成。下面,我们来实现一个简单的 SSE 控制器,它会每隔一段时间向客户端推送当前的时间信息 。

import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.reactive.function.BodyInserters; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.time.Duration; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @RestController @RequestMapping("/sse") public class SSEController { @GetMapping("/stream") public Flux<ServerSentEvent<String>> sendTime() { return Flux.interval(Duration.ofSeconds(1)) .map(sequence -> { LocalDateTime now = LocalDateTime.now(); String formattedTime = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); return ServerSentEvent.builder() .id(String.valueOf(sequence)) .event("time-update") .data("Current time is: " + formattedTime) .build(); }); } }

在这段代码中,Flux.interval(Duration.ofSeconds(1)) 创建了一个每秒发出一个事件的响应式流。ServerSentEvent.builder() 用于构建 ServerSentEvent 对象,该对象可以包含 id、event 和 data 等信息,完全符合 SSE 规范。map() 方法则将流中的每个事件映射为 ServerSentEvent ,并附带当前的时间信息 。

(三)编写客户端接收 SSE 数据

客户端可以借助 JavaScript 原生的 EventSource API 来接收服务器发送的 SSE 数据流。以下是一个简单的 HTML 页面示例,用于接收并展示服务器推送的时间信息:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>SSE Example</title> </head> <body> <h1>Server-Sent Events Example</h1> <div id="sse-data"></div> <script> const eventSource = new EventSource('/sse/stream'); eventSource.onmessage = function(event) { document.getElementById('sse-data').innerHTML += event.data + '<br>'; }; </script> </body> </html>

在上述代码中,EventSource("/sse/stream") 在客户端发起与服务器的 SSE 长连接,服务器通过 /sse/stream 推送事件。onmessage 事件处理函数则负责处理服务器发送的消息,并将消息显示在页面上 。

运行与验证

运行 Spring Boot 应用,当你访问
http://localhost:8080/sse/stream (假设你的应用运行在 8080 端口),就可以看到服务器每秒钟向客户端推送一次当前时间信息。你还可以通过浏览器打开包含上述 HTML 代码的页面,在页面中将会每秒钟显示一次服务器推送的数据流,这样就成功验证了 SSE 在 Spring Boot 3 中的实现 。

优化与扩展

为了模拟更真实的场景,可以增加一些随机数据或实时数据更新。比如,假设我们希望推送随机的股票价格,我们可以这样修改代码:

import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.reactive.function.BodyInserters; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.time.Duration; import java.util.Random; @RestController @RequestMapping("/sse") public class SSEController { private static final Random random = new Random(); @GetMapping("/stock-price") public Flux<ServerSentEvent<String>> sendStockPrice() { return Flux.interval(Duration.ofSeconds(3)) .map(sequence -> { double stockPrice = 100 + random.nextDouble() * 20; // 模拟股票价格在100 - 120之间波动 return ServerSentEvent.builder() .id(String.valueOf(sequence)) .event("stock-price-update") .data("Current stock price is: " + stockPrice) .build(); }); } }

同时,在客户端 HTML 页面中,修改 EventSource 的连接地址为 /sse/stock-price ,就可以接收并展示随机的股票价格信息了 。

另外,为了保持连接活跃,SSE 规范推荐发送 “ping” 消息。虽然 ServerSentEvent 是处理 SSE 的标准类,但你也可以直接返回 Flux<T> ,Spring 会自动将其转换为事件流。例如:

import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.reactive.function.BodyInserters; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.time.Duration; @RestController @RequestMapping("/sse") public class SSEController { @GetMapping(value = "/simple-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<String> simpleStream() { return Flux.interval(Duration.ofSeconds(2)) .map(sequence -> "This is a simple message at " + System.currentTimeMillis()); } }

在这个例子中,直接返回 Flux<String> ,Spring WebFlux 会自动推送数据 。

SSE 与 WebSocket 的抉择

SSE 和 WebSocket 都是实时通信领域的重要技术,但它们各自适用于不同的场景:

  • SSE:单向通信,服务器推送数据到客户端,特别适合轻量级的通知、监控、消息更新等场景。它使用简单,基于 HTTP 协议,在实现和维护上相对轻松 。
  • WebSocket:双向通信,适用于复杂的交互场景,如实时聊天、在线游戏等。WebSocket 是基于 TCP 的全双工连接,功能强大但相对复杂,对开发人员的要求也更高 。

对于简单的实时更新场景,比如股票价格更新、推送通知等,SSE 无疑是更加轻量且易于实现的选择 。

总结

Spring Boot 3 为我们提供了简单且强大的 SSE 实现方案,结合响应式编程的特性,能够让我们轻松构建出高效的服务器推送应用。在实际项目中,SSE 在推送实时数据或监控信息方面表现出色,尤其是在需要轻量且可靠的单向通信场景中 。通过 Spring WebFlux 和 Project Reactor,SSE 的实现可以以非阻塞的方式运行,极大地提升了应用的并发处理能力 。希望本文能帮助各位互联网软件开发人员在 Spring Boot3 的开发中,熟练运用 SSE 协议实现数据的实时推送,为打造更优秀的应用程序添砖加瓦 。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/7 18:23:38

异常 0-0

一、概念【理解即可】 1. 异常&#xff1a;程序运行过程中&#xff0c;出现的非正常情况。 2. 异常的处理&#xff1a;当异常出现时&#xff0c;执行一段预先准备好的代码。 3. 异常的处理的必要性&#xff1a;减少用户的损失、同时减小给用户带来麻烦&#xff0c;也可以对用户…

作者头像 李华
网站建设 2026/7/7 6:39:06

五、异常的处理【开发重点】

1. 消极处理异常(声明异常) (1) 关键字&#xff1a;throws (2) 位置&#xff1a;在方法声明的位置&#xff0c;进行消极处理异常 (3) 语法&#xff1a;修饰符 返回值类型 方法名(形参列表)throws 异常类名1,异常类名2,异常类名3{} (4) 结果&#xff1a;消极处理异常只是推卸责任…

作者头像 李华
网站建设 2026/7/7 20:03:39

NumCpp实战指南:高性能C++数值计算从入门到精通

NumCpp实战指南&#xff1a;高性能C数值计算从入门到精通 【免费下载链接】NumCpp C implementation of the Python Numpy library 项目地址: https://gitcode.com/gh_mirrors/nu/NumCpp 引言&#xff1a;为什么选择NumCpp&#xff1f; 在现代科学计算和数据分析领域&a…

作者头像 李华
网站建设 2026/7/7 12:34:33

水土保持方案编制】深度拆解八大项目类型:点型、市政、线型、矿山、水利、取土弃渣场、补报项目及监测验收,附海量案例与避坑指南!

您是否曾在编制水土保持方案时&#xff0c;因项目类型特殊而无从下手&#xff1f;是否在现场踏勘中遗漏关键细节&#xff0c;导致方案反复修改&#xff1f;是否在面对矿山修复、线性工程巨大的土石方量或复杂的弃渣场设计时感到力不从心&#xff1f;又是否对补报项目的特殊性、…

作者头像 李华
网站建设 2026/7/7 6:51:36

RouterOS 7.19 x86版本深度解析:企业级网络管理的革命性升级

RouterOS 7.19 x86版本深度解析&#xff1a;企业级网络管理的革命性升级 【免费下载链接】MikroTikPatch 项目地址: https://gitcode.com/gh_mirrors/mikr/MikroTikPatch MikroTikPatch项目作为专注于RouterOS系统补丁和版本管理的开源解决方案&#xff0c;持续跟踪并深…

作者头像 李华
网站建设 2026/7/7 18:11:53

Wan2.2-T2V-A14B在教育培训视频自动生成中的潜力挖掘

Wan2.2-T2V-A14B在教育培训视频自动生成中的潜力挖掘 你有没有想过&#xff0c;有一天老师只需要敲几行字&#xff0c;就能“召唤”出一节生动的物理课&#xff1f; 比如&#xff1a;“生成一个关于牛顿第一定律的教学视频&#xff0c;黑板上有公式&#xff0c;老师比划手势&am…

作者头像 李华