一分钟搞定SpringBoot+Vue3 整合 SSE 实现实时消息推送

我把 SpringBoot + Vue3 整合 SSE ​ 的文章写得更加详细,包括依赖引入、配置说明、完整代码、测试方法和注意事项,让你真正可以"一分钟开箱即用"。


一、技术原理简介

SSE(Server-Sent Events) ​ 是一种基于 HTTP 的服务器向客户端单向实时通信技术。

特点:

  • 基于标准 HTTP 协议,无需 WebSocket 复杂握手。
  • 服务端保持长连接,随时推送数据。
  • 浏览器原生支持 EventSourceAPI。
  • 适合 通知推送、实时日志、股票行情、聊天消息(单向) 等场景。

二、后端:SpringBoot 实现 SSE

1. 引入依赖

使用 Maven 的 pom.xml引入 Spring Boot Web 依赖(Spring Boot 自带 SSE 支持,无需额外 jar):

xml 复制代码
<dependencies>
    <!-- Spring Boot Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- 测试用:方便发 POST 请求 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

说明spring-boot-starter-web已经包含了 javax.servlet-api和 Spring MVC,SseEmitter类位于 org.springframework.web.servlet.mvc.method.annotation.SseEmitter,无需额外引入 jar。


2. 配置文件

application.yml(或 application.properties)保持默认即可,无需特殊配置。

如果需要跨域,可以加:

yaml 复制代码
spring:
  web:
    cors:
      allowed-origins: "*"

3. SSE 控制器代码

less 复制代码
package com.example.sse.controller;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@RestController
@RequestMapping("/sse")
public class SseController {

    // 保存每个用户的 SSE 连接,生产环境可用 Redis 等分布式缓存
    private final Map<String, SseEmitter> emitters = new ConcurrentHashMap<>();

    /**
     * 客户端订阅接口
     * GET /sse/subscribe/{userId}
     */
    @GetMapping(value = "/subscribe/{userId}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter subscribe(@PathVariable String userId) {
        // 0 表示永不超时,如需超时可用 60_000 毫秒
        SseEmitter emitter = new SseEmitter(0L);
        emitters.put(userId, emitter);

        // 完成时移除
        emitter.onCompletion(() -> emitters.remove(userId));
        // 超时移除
        emitter.onTimeout(() -> emitters.remove(userId));
        // 出错移除
        emitter.onError((e) -> emitters.remove(userId));

        return emitter;
    }

    /**
     * 服务端推送消息接口
     * POST /sse/push/{userId}
     */
    @PostMapping("/push/{userId}")
    public void push(@PathVariable String userId, @RequestBody String message) {
        SseEmitter emitter = emitters.get(userId);
        if (emitter != null) {
            try {
                // name("message") 对应前端的 event type
                emitter.send(SseEmitter.event().name("message").data(message));
            } catch (IOException e) {
                emitters.remove(userId);
            }
        }
    }
}

4. 启动类

typescript 复制代码
package com.example.sse;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SseApplication {
    public static void main(String[] args) {
        SpringApplication.run(SseApplication.class, args);
    }
}

三、前端:Vue3 连接 SSE

1. 创建 Vue3 项目

sql 复制代码
npm create vite@latest sse-demo -- --template vue
cd sse-demo
npm install

2. 组件代码

src/components/SseDemo.vue

xml 复制代码
<template>
  <div>
    <h3>SSE 实时消息推送</h3>
    <ul>
      <li v-for="(msg, index) in messages" :key="index">{{ msg }}</li>
    </ul>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'

const messages = ref([])
let eventSource = null

onMounted(() => {
  // 替换为你的后端地址和 userId
  eventSource = new EventSource('http://localhost:8080/sse/subscribe/user123')

  // 接收消息
  eventSource.onmessage = (event) => {
    messages.value.push(event.data)
  }

  // 错误处理
  eventSource.onerror = (err) => {
    console.error('SSE connection error:', err)
    eventSource.close()
  }
})

onBeforeUnmount(() => {
  if (eventSource) {
    eventSource.close()
  }
})
</script>

3. 在 App.vue 中使用

xml 复制代码
<template>
  <SseDemo />
</template>

<script setup>
import SseDemo from './components/SseDemo.vue'
</script>

四、测试方法

  1. 启动 SpringBoot 后端

    默认端口 8080。

  2. 启动 Vue3 前端

    arduino 复制代码
    npm run dev

    打开浏览器访问 http://localhost:5173

  3. 发送测试消息

    用 Postman 或 curl 发 POST 请求:

    bash 复制代码
    curl -X POST http://localhost:8080/sse/push/user123 \
    -H "Content-Type: application/json" \
    -d '"Hello SSE 实时消息!"'

    前端页面会立刻收到并显示消息。


五、注意事项与优化

  1. 跨域问题

    前后端分离时,后端需配置 CORS,否则浏览器会拦截 EventSource 连接。

  2. 心跳保活

    长时间无消息时,连接可能被代理或浏览器断开。可在服务端定时推送注释行保持活跃:

    less 复制代码
    emitter.send(SseEmitter.event().comment("heartbeat"));
  3. 多用户广播

    当前示例是点对点(一个用户一个连接),如需群发,可维护一个 List<SseEmitter>或按频道分组。

  4. 生产环境

    • 使用 Redis 或消息队列管理连接,支持集群。
    • 设置合理的超时时间与重连机制。
    • 对敏感消息加密传输(HTTPS)。

总结

  • 后端:SseEmitter+ @GetMapping(produces=TEXT_EVENT_STREAM_VALUE)
  • 前端:new EventSource(url)+ onmessage接收
  • 引入 jar:仅需 spring-boot-starter-web,零额外依赖。
相关推荐
早已忘记2 分钟前
CI相关项
java·前端·ci/cd
小码哥_常7 小时前
Spring Boot 牵手Spring AI,玩转DeepSeek大模型
后端
freewlt7 小时前
前端性能优化实战:从 Lighthouse 分数到用户体验的全面升级
前端·性能优化·ux
0xDevNull7 小时前
Java反射机制深度解析:从原理到实战
java·开发语言·后端
小小亮017 小时前
Next.js基础
开发语言·前端·javascript
华洛8 小时前
我用AI做了一个48秒的真人精品漫剧,不难也不贵
前端·javascript·后端
WZTTMoon8 小时前
Spring Boot 中Servlet、Filter、Listener 四种注册方式全解析
spring boot·后端·servlet
standovon8 小时前
Spring Boot整合Redisson的两种方式
java·spring boot·后端
Novlan18 小时前
我把 Claude Code 里的隐藏彩蛋提取出来了——零依赖的 ASCII 虚拟宠物系统
前端
Cosolar9 小时前
LlamaIndex RAG 本地部署+API服务,快速搭建一个知识库检索助手
后端·openai·ai编程