Spring Boot 应用中实现基本的 SSE 功能
SSE 技术简介
SSE(Server-Sent Events)是一种允许服务器主动向客户端推送数据的技术。它基于 HTTP 长连接,使用简单,特别适合实时数据更新场景,如股票行情、新闻推送等。与 WebSocket 相比,SSE 更轻量级,且只支持服务器到客户端的单向通信。
Spring Boot 集成 SSE
下面我将介绍如何在 Spring Boot 中实现 SSE 功能:
1. 添加依赖
首先在 pom.xml
中添加 Spring Web 依赖:
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
</dependencies>
2. 创建 SSE 控制器
以下是一个简单的 SSE 控制器示例,它可以定时向客户端推送消息:
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 页面来接收服务器推送的消息:
<!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>
运行和测试
- 启动 Spring Boot 应用
- 访问客户端页面(例如:
http://localhost:8080/index.html
) - 点击 “Start SSE” 按钮开始接收服务器推送的消息
- 点击 “Stop SSE” 按钮停止接收消息
关键技术点说明
-
服务器端:
- 使用
SseEmitter
处理 SSE 连接 - 设置适当的超时时间
- 实现错误处理和连接关闭逻辑
- 使用
MediaType.TEXT_EVENT_STREAM_VALUE
指定响应类型
- 使用
-
客户端:
- 使用
EventSource
对象连接到 SSE 服务器 - 监听
message
事件接收服务器推送的数据 - 监听
error
事件处理连接错误 - 使用
close()
方法关闭连接
- 使用
注意事项
- 生产环境中应考虑使用连接池和更健壮的错误处理机制
- 长时间运行的 SSE 连接可能需要处理网络中断和重连问题
- 考虑添加身份验证和授权机制保护 SSE 端点
- 对于大量并发连接,应评估服务器性能和资源消耗
通过以上步骤,你可以在 Spring Boot 应用中实现基本的 SSE 功能,实现服务器向客户端的实时数据推送。