news 2026/3/14 16:35:13

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进行投诉反馈,一经查实,立即删除!