写一个springboot的sse通讯协议接口
时间: 2025-06-06 18:35:47 浏览: 33
<think>好的,我现在需要帮用户写一个Spring Boot的SSE通信协议接口。首先,我得回忆一下SSE是什么。SSE全称是Server-Sent Events,是一种服务器向客户端单向实时推送数据的技术,基于HTTP协议,使用长连接。适用于实时更新比如股票价格、新闻推送等场景。
接下来,我得确定在Spring Boot中如何实现SSE。记得Spring MVC提供了对SSE的支持,主要是通过返回SseEmitter对象。需要处理的是,当客户端连接到这个接口时,服务器保持连接打开,并定期发送数据。
首先,用户需要一个接口,所以得创建一个Controller类,里面有一个处理SSE请求的方法。这个方法应该返回SseEmitter对象。可能还需要一个服务类来管理这些emitter,比如注册新的客户端连接,并在有数据时发送给所有客户端。
需要考虑的问题:如何保持连接?如何发送数据?是否需要处理客户端断开的情况?可能需要维护一个SseEmitter的列表,当有事件发生时,遍历列表发送数据。同时,SseEmitter有超时时间,需要设置合理的超时,并且在超时或错误时从列表中移除。
步骤大概是这样的:
1. 创建Controller,提供一个GET接口,返回SseEmitter。
2. 在Controller或者一个Service类中维护一个SseEmitter的集合,比如ConcurrentHashMap,因为可能有多个线程同时操作。
3. 当客户端连接时,创建SseEmitter,设置超时时间和回调,当超时或完成时从集合中移除。
4. 可能需要另一个接口或者方法触发数据发送,比如定时任务,或者外部事件触发。
5. 在发送数据时,遍历所有注册的SseEmitter,调用send方法发送数据,处理可能的异常,比如客户端已经断开,这时候需要移除emitter。
可能的代码结构:在Controller中有一个/sse的端点,当访问时加入emitter到集合中。然后有一个定时任务每隔一段时间发送数据。或者用户可以根据需要触发发送。
需要注意的点:SseEmitter默认的超时时间是30秒,可能需要设置更长的时间,或者根据需求调整。此外,跨域问题,如果前端和Spring Boot应用不在同一个域,需要处理CORS配置。
示例代码的大致流程:
- 创建RestController,使用@GetMapping映射到/sse。
- 在方法中创建SseEmitter,添加到集合。
- 设置onCompletion和onTimeout回调,从集合中移除emitter。
- 另外,可能需要一个循环或者事件来触发数据发送,例如使用Scheduled注解定时发送。
然后测试的时候,可以使用前端页面,使用EventSource对象连接/sse端点,监听消息。
可能的错误点:忘记处理回调导致内存泄漏,或者没有正确发送数据格式。SSE要求数据格式为"data: "开头,后面跟内容,换行两次结束。但Spring的SseEmitter应该会自动处理这些格式,所以发送时只需要发送对象,或者字符串,框架会处理。
是否需要返回特定的媒体类型?是的,SSE需要MediaType.TEXT_EVENT_STREAM_VALUE,所以在GetMapping中设置produces = MediaType.TEXT_EVENT_STREAM_VALUE。
现在把这些整合成代码示例,确保步骤正确,并处理可能的异常情况。例如,在发送数据时捕获IOException,移除无效的emitter。
另外,可能用户希望有一个触发发送的接口,比如POST请求触发服务器向所有客户端推送消息,或者使用定时任务自动发送。根据用户的需求,可能需要不同的实现方式。
总结步骤:
1. 添加Spring Boot Web依赖。
2. 创建Controller,处理/sse端点,返回SseEmitter,并管理emitter集合。
3. 设置回调处理断开连接的情况。
4. 实现数据发送逻辑,比如定时任务或者另一个接口触发。
5. 处理跨域(如果需要)。
6. 测试。
现在根据这些思路写出示例代码,并解释每一步的作用,让用户能理解如何实现SSE接口。</think>以下是一个使用 Spring Boot 实现 SSE(Server-Sent Events)通信的示例,包含详细步骤和代码说明:
---
### 1. 添加依赖
确保 `pom.xml` 中包含 Spring Web 依赖:
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
```
---
### 2. 创建 SSE 控制器
```java
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.CopyOnWriteArrayList;
@RestController
public class SseController {
// 线程安全的列表,保存所有客户端连接
private final CopyOnWriteArrayList<SseEmitter> emitters = new CopyOnWriteArrayList<>();
// SSE 接口
@GetMapping(path = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter handleSse() {
SseEmitter emitter = new SseEmitter(60_000L); // 超时时间设为60秒
// 将新连接添加到列表
emitters.add(emitter);
// 设置连接完成和超时的回调(移除列表中的连接)
emitter.onCompletion(() -> emitters.remove(emitter));
emitter.onTimeout(() -> emitters.remove(emitter));
return emitter;
}
// 触发向所有客户端发送消息(示例:定时任务或外部调用)
public void sendEvents() {
String message = "Server Time: " + System.currentTimeMillis();
// 遍历所有连接并发送消息
emitters.forEach(emitter -> {
try {
emitter.send(message);
} catch (IOException e) {
// 发送失败时移除连接
emitters.remove(emitter);
}
});
}
}
```
---
### 3. 添加定时任务发送消息
在 Spring Boot 启动类或配置类中启用定时任务:
```java
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
@EnableScheduling
public class SseScheduler {
private final SseController sseController;
public SseScheduler(SseController sseController) {
this.sseController = sseController;
}
// 每3秒触发一次消息发送
@Scheduled(fixedRate = 3000)
public void triggerEvents() {
sseController.sendEvents();
}
}
```
---
### 4. 处理跨域问题(可选)
如果前端与后端域名不同,在 `@SpringBootApplication` 启动类中添加全局 CORS 配置:
```java
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/sse")
.allowedOrigins("http://localhost:3000"); // 允许前端域名
}
};
}
```
---
### 5. 前端测试代码
使用 HTML + JavaScript 监听 SSE 事件:
```html
<!DOCTYPE html>
<html>
<body>
<script>
const eventSource = new EventSource('http://localhost:8080/sse');
eventSource.onmessage = (event) => {
console.log('Received message:', event.data);
};
eventSource.onerror = (error) => {
console.error('SSE Error:', error);
};
</script>
</body>
</html>
```
---
### 关键点说明
1. **SseEmitter**:Spring 提供的 SSE 对象,用于保持长连接。
2. **线程安全集合**:使用 `CopyOnWriteArrayList` 安全地管理多个客户端连接。
3. **超时与回调**:设置 `onCompletion` 和 `onTimeout` 清理无效连接,避免内存泄漏。
4. **消息格式**:Spring 自动将 `emitter.send()` 的内容转换为 SSE 格式(如 `data: ...`)。
5. **触发机制**:通过定时任务或外部事件调用 `sendEvents()` 主动推送消息。
---
### 测试步骤
1. 启动 Spring Boot 应用。
2. 打开 HTML 页面,浏览器控制台会每3秒打印一次服务器时间。
3. 查看网络请求,确认 SSE 连接状态为“pending”(表示长连接正常)。
通过这种方式,你可以轻松实现服务器向客户端的实时单向通信。
阅读全文
相关推荐
















