在Web开发中,实现服务器向客户端推送实时数据的需求越来越普遍。Server-Sent Events(SSE)是一种允许服务器向客户端推送更新(例如,股票价格、新闻更新等)的技术,且这些更新可以自动在客户端上进行处理。Spring Framework提供了SseEmitter
类,以便在Spring MVC应用中方便地实现SSE功能。
什么是SseEmitter?
SseEmitter
是Spring MVC中用于发送服务器发送事件(SSE)的类。它允许你在服务器端创建并发送事件流,这些事件流可以包含文本数据、ID、事件类型等信息,并且客户端可以使用JavaScript的EventSource
对象来接收这些事件。
SseEmitter的主要参数和方法
- send(SseEmitter.SseEventBuilder event): 发送一个SSE事件。
- complete(): 完成事件流的发送,关闭连接。
- send(Publisher<SseEmitter.SseEventBuilder> events): 发送一个异步的事件流。
- setReconnectDelay(long delay): 设置客户端在断开连接后尝试重新连接的延迟时间(毫秒)。
- setMediaType(MediaType mediaType): 设置发送的媒体类型,默认为
text/event-stream
。
- setCommentPrefix(String commentPrefix): 设置注释前缀,用于在发送的数据前添加注释(通常用于调试)。
- setIdleTimeout(Duration timeout): 设置空闲超时时间,在指定时间内如果没有发送任何数据,连接将关闭。
使用示例
以下是一个简单的Spring MVC控制器示例,它使用SseEmitter
来发送SSE事件。
1. 添加依赖
确保你的Spring Boot项目中包含了Web依赖。在pom.xml
中添加以下依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
2. 创建控制器
创建一个Spring MVC控制器,用于处理SSE请求。
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.sse.SseEmitter;
import reactor.core.publisher.Flux;
import java.io.IOException;
import java.time.Duration;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@RestController
public class SseController {
// 用于存储所有活动的SseEmitter实例
private final ConcurrentMap<String, SseEmitter> emitters = new ConcurrentHashMap<>();
@GetMapping(value = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter streamEvents() {
SseEmitter emitter = new SseEmitter(Duration.ofMinutes(1)); // 设置空闲超时时间为1分钟
emitter.setReconnectDelay(2000); // 设置重新连接延迟为2秒
// 将emitter添加到映射中,以便稍后可以访问它
String emitterKey = UUID.randomUUID().toString();
emitters.put(emitterKey, emitter);
// 使用Flux发送异步事件流
Flux<SseEmitter.SseEventBuilder> events = Flux.interval(Duration.ofSeconds(5))
.map(sequence -> SseEmitter.event()
.data("Event " + sequence)
.id(emitterKey)
.name("custom-event-type")
.build());
emitter.send(events);
// 清理:在emitter完成后从映射中移除
emitter.onComplete(() -> emitters.remove(emitterKey));
return emitter;
}
// 提供一个端点来手动发送事件到所有活动的客户端
@GetMapping("/sendEvent")
public String sendEvent() throws IOException {
for (SseEmitter emitter : emitters.values()) {
if (!emitter.isComplete()) {
emitter.send(SseEmitter.event().data("Broadcast Event").build());
}
}
return "Event broadcast to all clients.";
}
}
在Web开发中,实现服务器向客户端推送实时数据的需求越来越普遍。Server-Sent Events(SSE)是一种允许服务器向客户端推送更新(例如,股票价格、新闻更新等)的技术,且这些更新可以自动在客户端上进行处理。Spring Framework提供了SseEmitter
类,以便在Spring MVC应用中方便地实现SSE功能。
什么是SseEmitter?
SseEmitter
是Spring MVC中用于发送服务器发送事件(SSE)的类。它允许你在服务器端创建并发送事件流,这些事件流可以包含文本数据、ID、事件类型等信息,并且客户端可以使用JavaScript的EventSource
对象来接收这些事件。
SseEmitter的主要参数和方法
- send(SseEmitter.SseEventBuilder event): 发送一个SSE事件。
- complete(): 完成事件流的发送,关闭连接。
- send(Publisher<SseEmitter.SseEventBuilder> events): 发送一个异步的事件流。
- setReconnectDelay(long delay): 设置客户端在断开连接后尝试重新连接的延迟时间(毫秒)。
- setMediaType(MediaType mediaType): 设置发送的媒体类型,默认为
text/event-stream
。
- setCommentPrefix(String commentPrefix): 设置注释前缀,用于在发送的数据前添加注释(通常用于调试)。
- setIdleTimeout(Duration timeout): 设置空闲超时时间,在指定时间内如果没有发送任何数据,连接将关闭。
使用示例
以下是一个简单的Spring MVC控制器示例,它使用SseEmitter
来发送SSE事件。
1. 添加依赖
确保你的Spring Boot项目中包含了Web依赖。在pom.xml
中添加以下依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
2. 创建控制器
创建一个Spring MVC控制器,用于处理SSE请求。
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.sse.SseEmitter;
import reactor.core.publisher.Flux;
import java.io.IOException;
import java.time.Duration;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@RestController
public class SseController {
// 用于存储所有活动的SseEmitter实例
private final ConcurrentMap<String, SseEmitter> emitters = new ConcurrentHashMap<>();
@GetMapping(value = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter streamEvents() {
SseEmitter emitter = new SseEmitter(Duration.ofMinutes(1)); // 设置空闲超时时间为1分钟
emitter.setReconnectDelay(2000); // 设置重新连接延迟为2秒
// 将emitter添加到映射中,以便稍后可以访问它
String emitterKey = UUID.randomUUID().toString();
emitters.put(emitterKey, emitter);
// 使用Flux发送异步事件流
Flux<SseEmitter.SseEventBuilder> events = Flux.interval(Duration.ofSeconds(5))
.map(sequence -> SseEmitter.event()
.data("Event " + sequence)
.id(emitterKey)
.name("custom-event-type")
.build());
emitter.send(events);
// 清理:在emitter完成后从映射中移除
emitter.onComplete(() -> emitters.remove(emitterKey));
return emitter;
}
// 提供一个端点来手动发送事件到所有活动的客户端
@GetMapping("/sendEvent")
public String sendEvent() throws IOException {
for (SseEmitter emitter : emitters.values()) {
if (!emitter.isComplete()) {
emitter.send(SseEmitter.event().data("Broadcast Event").build());
}
}
return "Event broadcast to all clients.";
}
}
3. 前端代码
在前端,你可以使用JavaScript的EventSource
对象来接收SSE事件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SSE Demo</title>
</head>
<body>
<h1>Server-Sent Events Demo</h1>
<div id="events"></div>
<script>
const eventSource = new EventSource('/sse');
eventSource.onmessage = function(event) {
const eventsDiv = document.getElementById('events');
const newElement = document.createElement("div");
newElement.innerHTML = "Received: " + event.data;
eventsDiv.appendChild(newElement);
};
eventSource.onerror = function(event) {
console.error("EventSource failed:", event);
};
// 可选:监听自定义事件类型
eventSource.addEventListener('custom-event-type', function(event) {
console.log('Custom event type received:', event.data);
});
</script>
</body>
</html>
总结
通过使用Spring Framework的SseEmitter
类,你可以轻松地在Spring MVC应用中实现SSE功能,从而允许服务器向客户端实时推送数据。在上面的示例中,我们创建了一个简单的控制器,它使用SseEmitter
发送事件流,并提供了一个端点来手动向所有连接的客户端广播事件。前端代码使用EventSource
对象来接收并处理这些事件。