流式接口通常用于持续不断地传输数据,例如推送日志、实时监控数据、消息订阅等场景。本文提供两种常见的实现方案:使用 Servlet 方式的 Server-Sent Events (SSE)(采用 SseEmitter 对象)以及基于响应式编程的 Spring WebFlux(利用 Flux 流)。

【前提条件】

  1. 已安装 JDK 8 及以上版本。
  2. 使用 Maven 或 Gradle 构建 Spring Boot 项目。
  3. 理解基本的 Spring Boot 开发流程以及 REST API 的开发。

【方案一:基于 SseEmitter 实现 SSE 流式接口】

SseEmitter 是 Spring MVC 提供的一个工具类,可以很方便地实现服务端向客户端单向推送数据。下面给出一个简单的示例代码:


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.ExecutorService;
import java.util.concurrent.Executors;

@RestController
public class SseStreamController {

    @GetMapping("/stream/sse")
    public SseEmitter streamSse() {
        // 设置 SseEmitter 默认超时时间为 30 分钟
        SseEmitter emitter = new SseEmitter(30 * 60 * 1000L);

        // 使用线程池异步发送数据
        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.execute(() -> {
            try {
                for (int i = 1; i <= 10; i++) {
                    // 构造数据,比如这里发送纯文本消息
                    String data = "当前 event 数据:" + i;
                    emitter.send(data);
                    // 模拟延时,1 秒一条数据
                    Thread.sleep(1000);
                }
                // 所有数据发送完成后关闭 emitter
                emitter.complete();
            } catch (IOException | InterruptedException e) {
                emitter.completeWithError(e);
            } finally {
                executor.shutdown();
            }
        });
        return emitter;
    }
}

【说明】

  1. 客户端请求【GET /stream/sse】时,将会建立一个 SSE 连接。
  2. 服务器在独立线程中每秒发送一条消息,客户端能实时接收到数据。
  3. 流程结束后,通过 emitter.complete() 通知客户端数据发送完毕。

在前端页面中,可以通过 JavaScript 的 EventSource 对象来订阅该 SSE 流,例如:


const eventSource = new EventSource('/stream/sse');
eventSource.onmessage = function(event) {
    console.log("接收到数据:", event.data);
};
eventSource.onerror = function(err) {
    console.error("错误:", err);
};

【方案二:基于 Spring WebFlux 实现 Reactive 流式接口】

Spring WebFlux 提供响应式编程支持,通过 Reactor 的 Flux 能够轻松实现流式数据传输。示例如下:


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 ReactiveStreamController {

    @GetMapping(value = "/stream/flux", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> streamFlux() {
        // 每隔 1 秒发送一条数据,共发送 10 条
        return Flux.interval(Duration.ofSeconds(1))
                   .map(sequence -> "响应式流数据:" + (sequence + 1))
                   .take(10);
    }
}

【说明】

  1. 在 @GetMapping 中设置 produces = MediaType.TEXT_EVENT_STREAM_VALUE 表示以 SSE 格式推送数据。
  2. Flux.interval(...) 每隔一秒生成一个递增的数字序列,然后通过 map 操作转换成字符串消息。
  3. take(10) 限制只发送 10 个数据,流结束后自动关闭。

这种方式适用于响应式编程,并且可以充分利用 Reactor 框架的特性实现复杂数据流逻辑。

──────────────────────────────
【项目配置说明】

  1. 如果选择方案一(SseEmitter),确保在 pom.xml 中引入 spring-boot-starter-web:

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

  2. 如果选择方案二(基于 WebFlux),则需要引入 spring-boot-starter-webflux:

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>

根据需求选择对应方案,如果项目中同时需要传统 MVC 和响应式编程,建议了解二者的区别,并合理拆分接口与模块。

──────────────────────────────
【调试与测试】

  1. 直接运行 Spring Boot 项目后,通过浏览器或 Postman 访问:
    • SSE 示例地址:http://localhost:8080/stream/sse
    • Flux 示例地址:http://localhost:8080/stream/flux
  2. 使用开发者工具或前端代码观察持续流式数据的显示。

──────────────────────────────
【总结】

本文介绍了两种在 Java Spring Boot 中发布流式接口的方法:
• 基于 SseEmitter 实现基于 Servlet 的 Server-Sent Events;
• 基于 Spring WebFlux 与 Reactor 的响应式数据流。

两种方式各有优点:SseEmitter 写法简单适用于传统 Spring MVC 场景,而 Spring WebFlux 更适合构建高并发与响应快速的实时数据推送服务。开发者可根据项目需求选择合适的实现方式,最终实现实时向客户端推送数据的流式接口。

希望本文对你在 Java Spring Boot 中实现流式接口有所帮助。


奔跑的移动电源
1 声望0 粉丝