Springboot 实现Server-Sent Events的项目实践
在 Spring Boot 中,返回 text/event-stream
类型的响应通常用于实现 Server-Sent Events (SSE),这种方式允许服务器推送实时更新到浏览器。客户端通过 EventSource
API 监听并接收这些事件。Spring Boot 可以通过使用 @RestController
和 SseEmitter
来实现这一功能。
步骤 1:创建 SSE Controller 返回 text/event-stream
我们可以通过 @GetMapping
来创建一个 API,返回 text/event-stream
类型的数据。这个数据会是一个持续的流,浏览器会实时地接收它。
示例:通过 Spring Boot 返回 text/event-stream 类型的响应
- 控制器:在 Spring Boot 中定义一个返回
text/event-stream
类型的 API 接口。 - 使用
SseEmitter
:SseEmitter
是 Spring 提供的一个类,用于处理 Server-Sent Events 流。我们可以利用它来异步地向客户端推送数据。
示例 1:简单的 SSE 实现
在这个示例中,我们将创建一个简单的 Spring Boot 控制器,该控制器将返回一个实时的事件流(SSE)。
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; @RestController public class SseController { /** * 这个接口会返回一个持续的事件流,浏览器会通过 EventSource 接收 */ @GetMapping("/sse") public SseEmitter handleSse() { SseEmitter emitter = new SseEmitter(); // 启动一个新的线程模拟定期推送事件 new Thread(() -> { try { for (int i = 0; i < 10; i++) { // 向客户端发送数据 emitter.send("data: Event " + i + "\n\n"); Thread.sleep(1000); // 每秒发送一次 } emitter.complete(); // 发送完毕后,标记事件流完成 } catch (Exception e) { emitter.completeWithError(e); // 如果出现异常,标记事件流出错 } }).start(); return emitter; // 返回 SseEmitter 实例,它会处理异步流式数据 } }
说明:
SseEmitter
用于处理 SSE 连接。我们将数据通过emitter.send()
发送到客户端。- 事件通过
data: <message>
格式发送给客户端,注意每条消息以两个换行符结束(\n\n
)。 Thread.sleep(1000)
用于模拟每秒发送一个事件。如果你需要定期发送事件,可以通过类似的机制来实现。- 最后,通过
emitter.complete()
标记事件流结束。如果发生错误,则使用emitter.completeWithError()
。
步骤 2:前端接收 SSE 事件
在前端,使用 JavaScript 的 EventSource
API 接收服务器推送的事件。这个 API 会保持与服务器的连接,一旦有新的事件,浏览器会自动处理。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Server-Sent Events Example</title> </head> <body> <h1>Server-Sent Events Example</h1> <div id="messages"></div> <script> // 创建一个 EventSource 对象,连接到 /sse 接口 const eventSource = new EventSource("/sse"); // 每当接收到数据时,处理该事件 eventSource.onmessage = function(event) { const messagesDiv = document.getElementById('messages'); const message = document.createElement('p'); message.textContent = event.data; messagesDiv.appendChild(message); }; // 错误处理 eventSource.onerror = function(error) { console.error("EventSource failed:", error); }; </script> </body> </html>
步骤 3:配置 Spring Boot 启用异步支持
SSE 通常需要异步处理,因此在 Spring Boot 中启用异步支持是非常重要的。可以通过 @EnableAsync
来启用异步支持。
启用异步支持
import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; @Configuration @EnableAsync public class AsyncConfig { }
步骤 4:定时推送数据(可选)
如果你希望定期推送事件(例如,每隔一定时间推送一个消息),可以使用 Spring 的 @Scheduled
注解来安排定时任务。
示例:定时发送事件
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Controller; @Controller public class ScheduledSseController { private final SseEmitter emitter = new SseEmitter(); @Scheduled(fixedRate = 5000) // 每5秒发送一个事件 public void sendScheduledEvent() { try { emitter.send("data: Scheduled Event at " + System.currentTimeMillis() + "\n\n"); } catch (IOException e) { emitter.completeWithError(e); } } }
在上面的示例中,@Scheduled(fixedRate = 5000)
会定期每 5 秒发送一次事件。
步骤 5:处理多客户端连接
如果你需要管理多个客户端连接,可以将 SseEmitter
实例存储在一个列表中,并为每个连接发送事件。每当有新事件时,你可以通过遍历这些连接,发送事件到所有连接的客户端。
import org.springframework.stereotype.Controller; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import org.springframework.web.bind.annotation.GetMapping; import java.io.IOException; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @Controller public class MultiClientSseController { private final List<SseEmitter> emitters = new CopyOnWriteArrayList<>(); @GetMapping("/sse") public SseEmitter handleSse() { SseEmitter emitter = new SseEmitter(); emitters.add(emitter); // 在新线程中发送数据 new Thread(() -> { try { for (int i = 0; i < 10; i++) { for (SseEmitter e : emitters) { e.send("data: Event " + i + "\n\n"); } Thread.sleep(1000); // 每秒发送一次 } } catch (Exception e) { emitters.forEach(SseEmitter::completeWithError); } }).start(); return emitter; } }
总结
- 返回
text/event-stream
:在 Spring Boot 控制器中使用SseEmitter
或直接通过@GetMapping
返回流式数据。 - 前端接收事件:使用浏览器的
EventSource
API 来接收事件流。 - 定时事件:可以使用
@Scheduled
来定期推送事件,或者通过后台线程推送动态数据。 - 多客户端支持:可以管理多个
SseEmitter
实例,为每个客户端推送事件。
这种方式非常适合实时数据推送,例如股票行情更新、社交媒体通知、实时消息等应用场景。
到此这篇关于Springboot 实现Server-Sent Events的项目实践的文章就介绍到这了,更多相关Springboot实现Server-Sent Events内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Docker DockerFile部署java jar项目包及Mysql和Redis的详细过程
Dockerfile是一种用于构建Docker镜像的文件格式,可以通过Dockerfile部署Java项目,这篇文章主要给大家介绍了关于Docker DockerFile部署java jar项目包及Mysql和Redis的详细过程,需要的朋友可以参考下2023-12-12SpringBoot学习系列之MyBatis Plus整合封装的实例详解
MyBatis-Plus是一款MyBatis的增强工具(简称MP),为简化开发、提高效率,这篇文章给大家介绍MyBatis Plus整合封装的实例详解,感兴趣的朋友跟随小编一起看看吧2020-08-08
最新评论