轻松实现服务器事件主动推送到web端!Spring SseEmitter 详解

SseEmitter 是 Spring Framework 中用于服务器发送事件(Server-Sent Events, SSE)的类。SSE 是一种允许服务器推送更新到客户端的技术,通常用于实时更新的场景,如股票价格、实时消息、游戏状态等,又或者想要实现像ChatGPT那样的流式问答的效果。

以下是 SseEmitter 的一些关键点和使用方法:

关键点

  1. 服务器推送事件:与 WebSocket 不同,SSE 是单向通信,从服务器到客户端。客户端通过 HTTP 请求订阅事件,服务器在事件发生时推送数据。
  2. 基于 HTTP 协议:SSE 使用 HTTP 协议,客户端通过标准的 HTTP 请求订阅,服务器通过 HTTP 响应推送事件。
  3. 自动重连:大多数浏览器内置对 SSE 的支持,并且会在连接断开时自动尝试重新连接。
  4. 简单性:SSE 相对于 WebSocket 更加简单和轻量,适用于只需要服务器向客户端推送数据的应用场景。

使用方法

1. 添加依赖

确保你的项目中包含 Spring Web 依赖。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
2. 创建控制器

创建一个 REST 控制器来处理 SSE 请求。

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 {

    @GetMapping("/sse")
    public SseEmitter handleSse() {
        SseEmitter emitter = new SseEmitter();
        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

        executor.scheduleAtFixedRate(() -> {
            try {
                emitter.send("Hello at " + System.currentTimeMillis());
            } catch (IOException e) {
                emitter.completeWithError(e);
            }
        }, 0, 1, TimeUnit.SECONDS);

        emitter.onCompletion(executor::shutdown);

        return emitter;
    }
}
3. 客户端订阅

客户端可以使用 JavaScript 原生的 EventSource 对象来订阅事件。

<!DOCTYPE html>
<html>
<head>
    <title>SSE Example</title>
</head>
<body>
    <h1>SSE Example</h1>
    <div id="events"></div>
    <script>
        const eventSource = new EventSource('/sse');
        eventSource.onmessage = function(event) {
            const newElement = document.createElement("div");
            newElement.textContent = event.data;
            document.getElementById("events").appendChild(newElement);
        };
    </script>
</body>
</html>

解释

  1. 创建 SseEmitter 实例:在服务器端控制器中,通过调用 new SseEmitter() 创建一个 SseEmitter 实例。
  2. 定期发送消息:使用调度任务定期向客户端发送消息。SseEmittersend 方法用于发送事件。
  3. 处理异常:在发送消息时处理可能的 IOException,并通过 completeWithError 方法通知客户端连接终止。
  4. 客户端接收消息:客户端通过 EventSource 对象订阅服务器推送的事件,并通过 onmessage 处理接收到的消息。

注意事项

  1. 连接管理:需要合理管理 SseEmitter 的生命周期,确保在连接完成、错误或超时时正确关闭。
  2. 浏览器支持:SSE 是大多数现代浏览器支持的技术,但在一些老旧浏览器中可能不受支持。
  3. 数据格式:SSE 传输的数据格式是文本,通常使用 JSON 格式传输结构化数据。

SseEmitter 提供了一种简洁高效的方法来实现服务器到客户端的实时数据推送,适合于许多实时应用场景。

<think>好的,用户想了解如何在Spring WebFlux中使用SseEmitter工具类,包括方法、示例和详解。首先,我需要确认SseEmitter是否属于Spring WebFlux的一部分。根据已有的知识,SseEmitter其实是Spring MVC中的一个类,用于支持服务器发送事件SSE),而Spring WebFlux通常使用SseEmitter的响应式版本,比如通过ServerSentEvent类或者Flux来处理SSE流。 用户可能混淆了Spring MVC和Spring WebFlux的组件,需要指出这一点。但根据用户提供的引用内容,特别是引用[3]提到Spring WebFlux使用Mono和Flux进行响应式编程,因此正确的做法应该是使用WebFlux的响应式方式来创建SSE,而不是传统的SseEmitter。 接下来,我需要查找相关的资料,确认在WebFlux中如何实现SSE。通常,在WebFlux中,可以通过返回一个Flux<ServerSentEvent>来实现服务器发送事件。例如,使用@GetMapping并指定produces为MediaType.TEXT_EVENT_STREAM_VALUE,然后返回一个Flux流。 然后,需要考虑用户可能需要的示例代码。应该提供一个简单的Controller示例,展示如何生成并发送事件流。可能还需要解释每个步骤的作用,比如使用Flux.interval生成周期性事件,使用map转换数据为ServerSentEvent对象。 同时,要指出与Spring MVC中SseEmitter的区别,强调WebFlux的非阻塞特性以及如何利用响应式编程处理高并发场景。此外,可能需要提到相关的配置或依赖,确保用户能够正确运行示例。 还需要检查是否有引用文献支持这些信息。用户提供的引用[3]提到了Flux和Mono的使用,可以作为参考,说明在WebFlux中推荐使用这些响应式类型来处理数据流。而引用[1]和[2]可能不直接相关,但可以强调性能优化和安全性方面的考虑。 最后,确保回答结构清晰,分步骤说明使用方法,提供代码示例,并解释关键点。可能还需要提醒用户注意依赖项是否正确引入,比如Spring WebFlux和相关的响应式库。</think>### SseEmitterSpring WebFlux中的应用详解 #### 1. 核心概念说明 SseEmitterSpring框架中用于实现**服务器推送事件(Server-Sent Events)**的工具类,但在Spring WebFlux中更推荐使用响应式流`Flux<ServerSentEvent>`实现SSE功能[^3]。两者的核心差异在于: - 传统Spring MVC:使用`SseEmitter`进行阻塞式推送 - Spring WebFlux:通过`Flux`实现非阻塞流式响应 #### 2. 基础使用示例 ```java import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Flux; import java.time.Duration; @RestController public class SSEController { @GetMapping(value = "/stream-events", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<String> streamEvents() { return Flux.interval(Duration.ofSeconds(1)) .map(sequence -> "Event-" + sequence); } } ``` *代码说明*: - 通过`@GetMapping`指定`produces = TEXT_EVENT_STREAM_VALUE`声明SSE点 - `Flux.interval`每1秒生成一个递增数字 - `map`转换数字为事件字符串 #### 3. 进阶功能实现 ```java @GetMapping(value = "/advanced-events", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<ServerSentEvent<String>> advancedEvents() { return Flux.interval(Duration.ofSeconds(1)) .map(sequence -> ServerSentEvent.<String>builder() .id(String.valueOf(sequence)) .event("customEvent") .data("Data-" + sequence) .comment("Timestamp: " + System.currentTimeMillis()) .build()); } ``` *功能特性*: - 使用`ServerSentEvent`构建器自定义事件结构 - 支持设置事件ID、类型、数据、注释等元数据 - 自动处理心跳维持(通过持续流保持连接) #### 4. 客户接收示例 ```html <script> const eventSource = new EventSource('/advanced-events'); eventSource.onmessage = (e) => { console.log('Received:', e.data); }; eventSource.addEventListener('customEvent', (e) => { console.log('Custom event:', e); }); </script> ``` #### 5. 关键配置项 在`application.properties`中添加: ```properties # 设置响应缓冲区大小(默认256KB) spring.servlet.multipart.max-request-size=10MB # 设置流超时时间(默认30秒) spring.mvc.async.request-timeout=-1 # -1表示无超时 ``` #### 6. 性能优化建议 1. **背压控制**:使用`onBackpressureBuffer`处理消费者速度不足的情况 2. **异常处理**:通过`doOnError`添加错误处理逻辑 3. **资源释放**:使用`doFinally`确保流关闭时释放资源 4. **安全集成**:结合Spring Security进行点保护[^2] #### 7. 与传统SseEmitter的对比 | 特性 | WebFlux(Flux) | Spring MVC(SseEmitter) | |---------------------|---------------------|-------------------------| | 线程模型 | 非阻塞IO | 阻塞IO | | 内存消耗 | 更低(响应式背压) | 较高 | | 最大连接数 | 10K+ | 1K左右 | | 事件延迟 | 更稳定 | 受线程池限制 | | 错误处理 | 响应式操作符 | try-catch块 |
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值