Spring Boot中使用Server-Sent Events (SSE) 实现实时数据推送教程

一、简介

Server-Sent Events (SSE) 是HTML5引入的一种轻量级的服务器向浏览器客户端单向推送实时数据的技术。在Spring Boot框架中,我们可以很容易地集成并利用SSE来实现实时通信。

二、依赖添加

在Spring Boot项目中,无需额外引入特定的依赖,因为Spring Web MVC模块已经内置了对SSE的支持。

辅助Maven

        <!-- 集成beetl -->
        <dependency>
            <groupId>com.ibeetl</groupId>
            <artifactId>beetl-framework-starter</artifactId>
            <version>1.2.30.RELEASE</version>
        </dependency>

        <!-- 集成hutool工具类简便操作 -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.10</version>
        </dependency>

三、编写核心SSE Client

@Slf4j
@Component
public class SseClient {
    private static final Map<String, SseEmitter> sseEmitterMap = new ConcurrentHashMap<>();
    /**
     * 创建连接
     */
    public SseEmitter createSse(String uid) {
        //默认30秒超时,设置为0L则永不超时
        SseEmitter sseEmitter = new SseEmitter(0l);
        //完成后回调
        sseEmitter.onCompletion(() -> {
            log.info("[{}]结束连接...................", uid);
            sseEmitterMa
<think>嗯,用户想了解如何在Spring Boot后端和Vite+Vue3+TS前端中使用Server-Sent EventsSSE)。我需要先回忆一下SSE的基本概念和用途。SSE是一种服务器向客户端实时推送数据的技术,基于HTTP协议,适用于单向通信,比如实时通知、股票价格更新等场景。与WebSocket不同,SSE是单向的,只能服务器向客户端发送消息,但实现起来相对简单。 首先,后端Spring Boot部分。我记得Spring MVC或者WebFlux都支持SSE。需要创建一个控制器,返回SseEmitter对象。每个客户端连接会生成一个SseEmitter实例,用于发送事件。可能需要处理跨域问题,所以得加上@CrossOrigin注解或者配置全局CORS。此外,需要保持连接,定期发送数据,否则连接可能会超时断开。还要考虑异常处理和资源释放,比如在客户端断开时关闭emitter。 然后是前端部分,Vite+Vue3+TypeScript的环境。前端需要使用EventSource API来建立连接,监听服务器发送的事件。在Vue3中,可以在组件的onMounted钩子中创建EventSource,指定后端接口的URL。需要注意跨域问题,如果前后端域名不同,后端必须正确配置CORS。EventSource有open、message、error等事件需要处理,特别是错误处理可能需要重连机制。另外,在组件卸载时,应该关闭EventSource连接,避免内存泄漏。 可能用户的实际需求是做一个实时应用,比如消息推送或者数据监控。需要确保后端能够处理多个客户端的连接,管理好每个SseEmitter实例,避免内存泄漏。前端部分可能需要展示实时数据使用Vue3的响应式变量来更新界面。TypeScript的类型定义也需要考虑,比如定义事件的数据结构。 用户可能还关心如何传递数据格式,比如发送JSON数据后端需要设置media type为“application/json”或者“text/event-stream”,前端解析数据。此外,可能需要处理不同的event类型,或者重试时间等SSE特性。还有身份验证的问题,比如如何在SSE连接中传递token,可能需要使用URL参数或者cookie,因为EventSource默认不支持设置请求头。 需要提醒用户注意SSE的兼容性,虽然现代浏览器都支持,但某些环境下可能需要polyfill。另外,连接断开后的重连策略,EventSource默认会自动重连,但有时候可能需要手动处理。最后,给出一个简单的示例代码,让用户能够快速上手,并指出常见问题和解决方案,比如跨域、超时、数据格式等。</think>在后端 Spring Boot 和前端 Vite + Vue3 + TypeScript 中使用 Server-Sent Events (SSE) 实现实时通信的完整方案如下: --- ### 一、后端 Spring Boot 实现 #### 1. 添加依赖 ```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.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; @RestController @CrossOrigin(origins = "*") // 处理跨域 public class SseController { private final Map<String, SseEmitter> emitters = new ConcurrentHashMap<>(); // 前端连接入口 @GetMapping(path = "/sse/connect", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public SseEmitter connect(@RequestParam String userId) { SseEmitter emitter = new SseEmitter(60_000L); // 1分钟超时 emitters.put(userId, emitter); emitter.onCompletion(() -> emitters.remove(userId)); emitter.onTimeout(() -> emitters.remove(userId)); return emitter; } // 发送消息方法(可被其他服务调用) public void sendEvent(String userId, String data) { SseEmitter emitter = emitters.get(userId); if (emitter != null) { try { emitter.send(SseEmitter.event() .data(data) .id(UUID.randomUUID().toString()) .comment("SSE Event")); } catch (IOException e) { emitters.remove(userId); } } } } ``` #### 3. 配置项(可选) 在 `application.properties` 中调整: ```properties # 增加异步超时时间 spring.mvc.async.request-timeout=60000 ``` --- ### 二、前端 Vue3 + TS 实现 #### 1. 封装 SSE 工具类 ```typescript // src/utils/sse.ts interface SSEOptions { onMessage: (data: string) => void; onError?: (event: Event) => void; } export class SSEClient { private eventSource: EventSource | null = null; constructor(private url: string, private options: SSEOptions) {} connect(): void { this.eventSource = new EventSource(this.url); this.eventSource.onmessage = (event: MessageEvent) => { this.options.onMessage(event.data); }; this.eventSource.onerror = (error: Event) => { this.options.onError?.(error); this.close(); }; } close(): void { this.eventSource?.close(); } } ``` #### 2. 在 Vue 组件中使用 ```vue <script setup lang="ts"> import { onMounted, onUnmounted, ref } from 'vue' import { SSEClient } from '@/utils/sse' const messages = ref<string[]>([]) let sseClient: SSEClient | null = null onMounted(() => { // 连接 SSE(假设用户 ID 为 123) sseClient = new SSEClient('http://localhost:8080/sse/connect?userId=123', { onMessage: (data) => { messages.value.push(data) }, onError: (err) => { console.error('SSE Error:', err) } }) sseClient.connect() }) onUnmounted(() => { sseClient?.close() }) </script> <template> <div> <h2>实时消息:</h2> <ul> <li v-for="(msg, index) in messages" :key="index">{{ msg }}</li> </ul> </div> </template> ``` --- ### 三、关键注意事项 1. **跨域处理**: - 后端需配置 `@CrossOrigin` 或全局 CORS 配置 - 前端开发时在 `vite.config.ts` 配置代理: ```ts export default defineConfig({ server: { proxy: { '/sse': 'http://localhost:8080' } } }) ``` 2. **数据传输格式**: - 发送 JSON 数据后端使用: ```java emitter.send(SseEmitter.event().data(objectMapper.writeValueAsString(yourObject))); ``` - 前端解析: ```ts onMessage: (data) => { const parsed = JSON.parse(data) } ``` 3. **心跳机制**: ```java // 在后端定期发送空注释保持连接 emitter.send(SseEmitter.event().comment("")); ``` 4. **错误处理**: - 前端自动重连策略: ```ts onError: () => { setTimeout(() => this.connect(), 3000) } ``` --- ### 四、扩展场景示例 #### 发送结构化数据: ```java // 后端发送对象 emitter.send(SseEmitter.event() .data(new MessageDto("系统通知", "您有新消息"), MediaType.APPLICATION_JSON)); ``` ```ts // 前端定义类型 interface Message { title: string content: string } onMessage: (data) => { const msg = JSON.parse(data) as Message // 使用 msg.title / msg.content } ``` --- 通过以上实现,您可以建立稳定的 SSE 通信通道。典型应用场景包括实时通知、股票报价、日志推送等需要服务器主动推送的场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值