当前位置: 首页 > news >正文

SSE 实践:用 Vue 和 Spring Boot 实现实时数据传输

前言

大家好,我是雪荷。最近我在灵犀 BI 项目中引入了 SSE 技术,以保证图表的实时渲染,当图表渲染完毕服务端推送消息至浏览器端触发重新渲染。

什么是 SSE?

SSE 全称为 Server-Send Events 意思是服务端推送事件。

SSE 相比于 Websocket 它基于 Http 实现无需实现其他协议、更加轻量级、支持自动重连,但只能服务端推送消息给客户端,客户端不能推送消息给服务端。适用于服务端主动推送数据,客户端只需接收数据的场景。以下为 SSE 与 Websocket 的对比:

SSEWebsocket
通信单向通信(服务端到客户端)双向通信
协议HttpWebsocket
自动重连支持不支持,要客户端自行支持
数据格式文本格式,如果要二进制数据得自行编码默认二进制数据、支持文本格式
浏览器兼容性大部分支持主流浏览器支持较好

Vue + Spring Boot 实现一个 SSE demo

后端实现

由于 SSE 基于 http 协议实现,因此我们无需引入第三方 jar 包。首先通过 idea 创建一个 spring boot 项目,记得勾选 spring web 依赖。

image-20250117095658768

创建一个跨域配置,因为前后端的端口不同,会出现请求跨域。

@Configuration
public class CorsConfig implements WebMvcConfigurer {
​@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOriginPatterns("*").allowedMethods("GET", "POST", "PUT", "DELETE").allowedHeaders("*").allowCredentials(true);}
}
随后创建一个 SSEcontroller,用来创建 SSE 连接和推送消息给客户端。
@RestController
@RequestMapping("/sse")
public class SSEController {
​private static final Map<Integer, SseEmitter> sseEmitters = new ConcurrentHashMap<>();
​@GetMapping("/create")public SseEmitter createSSEConnection() {// 创建SSE连接SseEmitter emitter = new SseEmitter();// 将 sseEmitter 赛道 map 中,方便管理多个 sse 连接,比如可以为每个用户创建一个 sse 连接,以用户 id 为 map 的 keysseEmitters.put(1, emitter);emitter.onCompletion(() -> sseEmitters.remove(1));emitter.onTimeout(() -> sseEmitters.remove(1));return emitter;}
​@PostMapping("/send")public void sendSSEMessage() {// 发送消息SseEmitter sseEmitter = sseEmitters.get(1);if (sseEmitter != null) {for (int i = 0; i < 3; i++) {try {sseEmitter.send(SseEmitter.event().data("hello world") // 发送的数据,是 Object 类型.name("sse-message")); // 定义 SSE 事件的名称,方便前端监听} catch (IOException e) {sseEmitters.remove(1);}}}}
​
}

在上面的代码中,createSSEConnection 用来创建 sse 连接,注意其请求方法为 get,post 是不能创建的,因为前端发的就是 get 请求。我还创建了一个 sseEmitters 的 Map<Integer, SseEmitter> 来管理 sse 连接,在项目中 map 的 key 可以作为客户端标识,可以是用户 id 或者某些业务参数。当创建完毕后将 sseEmiter 塞到 map 中,当 sse 连接超时或者完成就删掉在 map 中对应的 value。

而 sendSSEMessage 方法就是服务端向客户端推送消息的实例代码,这里我们方便我写了一个请求来触发服务端发消息给客户端,实际是根据具体业务来主动推消息给客户端。比如异步生成图表或者插入数据时,当此动作完毕后可以发消息给前端表明操作成功。那如何发送消息就不用我说了,先从 map 取出 sseEmitter,接着添加事件名和要发送的数据就好了。

如果是前端传送参数来创建 sse 连接的话,可以这样操作。

    @GetMapping("/create")public SseEmitter createSSEConnection(@RequestParam Integer id) {// 创建SSE连接SseEmitter emitter = new SseEmitter();sseEmitters.put(id, emitter);emitter.onCompletion(() -> sseEmitters.remove(1));emitter.onTimeout(() -> sseEmitters.remove(1));return emitter;}

前端实现

首先创建一个 vue 项目,引入一些基础依赖,比如 aixos,项目具体结构如下:

image-20250117101231521

myAxios.js:

import axios from 'axios';
​
const myAxios = axios.create({baseURL: 'http://localhost:8080',
})
​
myAxios.defaults.withCredentials = true; //设置为true
​
​
export default myAxios;

然后 SSEDemo.vue 就是主要创建 sse 连接和接受服务端发送消息

SSEDemo.vue:

<template><div><h3>接收到的消息:</h3><ul><li v-for="(message, index) in messages" :key="index">{{ message }}</li></ul></div><button @click="sendMessage">发送消息</button>
</template>
​
<script>
import {onBeforeUnmount, onMounted, ref} from 'vue';
import myAxios from "@/plugins/myAxios.js";
​
export default {setup() {const messages = ref([]); // 存储接收到的消息let eventSource = null; // 用于保存 EventSource 实例
​onMounted(() => {// 创建 EventSource 实例,连接到服务器端的 SSE 端点eventSource = new EventSource('http://localhost:8080/sse/create');
​// 监听特定事件名 'sse-message'eventSource.addEventListener('sse-message', (event) => {console.log('收到消息:', event.data);// 解析消息并保存到 messages 中messages.value.push(event.data);});
​// 监听连接关闭或错误eventSource.onerror = (error) => {console.error('SSE 连接出错:', error);eventSource.close(); // 关闭连接};});
​onBeforeUnmount(() => {// 组件销毁时关闭 SSE 连接if (eventSource) {eventSource.close();}});
​const sendMessage = async () => {await myAxios.post('/sse/send');}
​return {messages,sendMessage};},
};
</script>

new EventSource 新建一个事件源,其会向后端发送请求方法为 get 的 http 请求,利用 eventSource.addEventListener 创建一个事件监听器并带上事件名就可以完成事件的监听和消息发送啦。

最后运行前后端项目,打开前端地址会看到有一个 http 显示待处理。

image-20250117102000639

点击发送消息按钮使后端发送消息给前端,前端接收到就会实时显示。

image-20250117102058899

开源项目

厚米匹配

网址:厚米匹配系统

前端仓库:https://github.com/dnwwdwd/homieMatching-fronted

后端仓库:https://github.com/dnwwdwd/homieMatching

灵犀 BI

网址:鱼智能 BI

前端仓库:https://github.com/dnwwdwd/Lingxi-BI-fronted

后端仓库:https://github.com/dnwwdwd/Lingxi-BI

http://www.lryc.cn/news/522842.html

相关文章:

  • TouchGFX学习笔记(一)
  • Java算法 二叉树入门 力扣简单题相同的树 翻转二叉树 判断对称二叉树 递归求二叉树的层数
  • 如何将 session 共享存储到 redis 中
  • vue3学习三
  • 彻底理解JVM类加载机制
  • 【计算机体系结构、微架构性能分析】core 与 uncore 分别是哪一些部分?区分 core 和 uncore
  • 鸿蒙打包发布
  • vue2:实现上下两栏布局,可拖拽改变高度
  • MongoDB 学习指南:深入探索非关系型数据库
  • 天机学堂3-ES+Caffeine
  • FPGA车牌识别
  • Pandas库的常用内容归纳
  • R语言的并发编程
  • STM32 FreeRTOS中断管理
  • 数据结构-栈和队列
  • RabbitMQ---TTL与死信
  • 第4章 Kafka核心API——Kafka客户端操作
  • Python爬虫学习前传 —— Python从安装到学会一站式服务
  • Lora理解QLoRA
  • Linux测试处理fps为30、1920*1080、一分钟的视频性能
  • Flink (六):DataStream API (三) 窗口
  • MYSQL学习笔记(二):基本的SELECT语句使用(基本、条件、聚合函数查询)
  • PCL 点到面的ICP算法实现点云配准(C++详细过程版)
  • MarsCode青训营打卡Day1(2025年1月14日)|稀土掘金-16.最大矩形面积问题
  • 我的世界-与门、或门、非门等基本门电路实现
  • 【FISCO BCOS】二十三、部署WeBASE-Node-Manager
  • app版本控制java后端接口版本管理
  • Go语言strings包与字符串操作:从基础到高级的全面解析
  • 使用redis-cli命令实现redis crud操作
  • Ubuntu升级Linux内核教程