SseEmitter:Spring Framework中的服务器端事件(Server-Sent Events, SSE)支持

在Web开发中,实现服务器向客户端推送实时数据的需求越来越普遍。Server-Sent Events(SSE)是一种允许服务器向客户端推送更新(例如,股票价格、新闻更新等)的技术,且这些更新可以自动在客户端上进行处理。Spring Framework提供了SseEmitter类,以便在Spring MVC应用中方便地实现SSE功能。

什么是SseEmitter?

SseEmitter是Spring MVC中用于发送服务器发送事件(SSE)的类。它允许你在服务器端创建并发送事件流,这些事件流可以包含文本数据、ID、事件类型等信息,并且客户端可以使用JavaScript的EventSource对象来接收这些事件。

SseEmitter的主要参数和方法

  1. send(SseEmitter.SseEventBuilder event): 发送一个SSE事件。
  2. complete(): 完成事件流的发送,关闭连接。
  3. send(Publisher<SseEmitter.SseEventBuilder> events): 发送一个异步的事件流。
  4. setReconnectDelay(long delay): 设置客户端在断开连接后尝试重新连接的延迟时间(毫秒)。
  5. setMediaType(MediaType mediaType): 设置发送的媒体类型,默认为text/event-stream
  6. setCommentPrefix(String commentPrefix): 设置注释前缀,用于在发送的数据前添加注释(通常用于调试)。
  7. 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.";
    }
}






扫描下方二维码,关注公众号:程序进阶之路,实时获取更多优质文章推送。


扫码关注

评论