当前位置: 首页 > 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

相关文章:

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

前言 大家好&#xff0c;我是雪荷。最近我在灵犀 BI 项目中引入了 SSE 技术&#xff0c;以保证图表的实时渲染&#xff0c;当图表渲染完毕服务端推送消息至浏览器端触发重新渲染。 什么是 SSE&#xff1f; SSE 全称为 Server-Send Events 意思是服务端推送事件。 SSE 相比于 …...

TouchGFX学习笔记(一)

配置请参考链接&#xff1a;TouchGFX超低配置移植教程-CSDN博客 一&#xff0c;显示配置 1.适当增加堆栈大小 2.适当增大缓冲大小 双重缓冲消除了任何撕裂的风险&#xff0c;无论渲染下一帧需要多长时间&#xff0c;因为TfT控制器&#xff0c;例如&#xff0c;总是可以访问最…...

Java算法 二叉树入门 力扣简单题相同的树 翻转二叉树 判断对称二叉树 递归求二叉树的层数

目录 模版 先序遍历 中序遍历 后序遍历 力扣原题 相同的二叉树 力扣原题 翻转二叉树 遍历树的层数 题目 静态变量 核心逻辑 模版 // 二叉树public static class Node{public int value;public Node left;public Node right;public Node(int v) {valuev;}} 先序遍历 …...

如何将 session 共享存储到 redis 中

文章目录 一. 分布式 session 登录1.1 什么是分布式&#xff1f;1.2 Session 共享1.3 为什么服务器 A 登录后&#xff0c;请求发到服务器 B&#xff0c;不认识该用户&#xff1f;1.4 共享存储 二. Session 共享实现Redis三. 测试session共享四. cookie设置4.1 前端4.2 后端 一.…...

vue3学习三

五 计算属性 定义 选项式 export default {data(){return {num:1}},computed:{num1(){this.num1}} } 组合式 import {ref,computed} from vuelet numref(0); //仅读 let num1 computed(()>{return num.value1 }) 计算时依赖的变量数据发生变化&#xff0c;则计算属性…...

彻底理解JVM类加载机制

文章目录 一、类加载器和双亲委派机制1.1、类加载器1.2、双亲委派机制1.3、自定义类加载器1.4、打破双亲委派机制 二、类的加载 图片来源&#xff1a;图灵学院   由上图可知&#xff0c;创建对象&#xff0c;执行其中的方法&#xff0c;在java层面&#xff0c;最重要的有获取…...

【计算机体系结构、微架构性能分析】core 与 uncore 分别是哪一些部分?区分 core 和 uncore

在计算机体系结构中&#xff0c;Core 和 Uncore 是描述处理器内部架构的两个重要概念&#xff0c;尤其在多核处理器中更为常见。 1. Core&#xff08;核心&#xff09; Core 指的是处理器中的计算核心&#xff0c;是执行指令和处理数据的基本单元。每个核心都包含独立的执行单…...

鸿蒙打包发布

HarmonyOS应用/元服务发布&#xff08;打包发布&#xff09; https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V13/ide-publish-app-V13?catalogVersionV13 密钥&#xff1a;包含非对称加密中使用的公钥和私钥&#xff0c;存储在密钥库文件中&#xff0c;格式…...

vue2:实现上下两栏布局,可拖拽改变高度

要拖拽改变两栏高度,那么总高度要确定,在拖拽的过程中,实时根据光标位置计算两栏高度,所以: 1、最外层有一个box, 高度是屏幕高度screenHeight; 2、该值在页面挂载时获取初始值(window.innerHeight-100),这里减少100,因为窗口上面有工具栏; 3、监听窗口resize事件…...

MongoDB 学习指南:深入探索非关系型数据库

MongoDB学习资料 MongoDB学习资料 MongoDB学习资料 在当今数字化时代&#xff0c;数据量呈爆炸式增长&#xff0c;数据结构也变得愈发复杂多样。传统的关系型数据库在处理一些大规模、高并发以及非结构化数据时&#xff0c;逐渐显露出局限性。而 MongoDB 作为一款领先的非关系…...

天机学堂3-ES+Caffeine

文章目录 day05-问答系统表 用户端分页查询问题目标效果代码实现 3.6.管理端分页查询问题ES相关 管理端互动问题分页实现三级分类3.6.5.2.多级缓存3.6.5.3.CaffeineTODO&#xff1a;使用Caffeine作为本地缓存&#xff0c;另外使用redis或者memcache作为分布式缓存&#xff0c;构…...

FPGA车牌识别

基于FPGA的车牌识别主要包含以下几个步骤&#xff1a;图像采集、颜色空间转换、边缘检测、形态学处理&#xff08;腐蚀和膨胀&#xff09;、特征值提取、模板匹配、结果显示。先用matlab对原理进行仿真&#xff0c;后用vivado和modelsim进行设计和仿真。 一、1.图像采集采用ov…...

Pandas库的常用内容归纳

Pandas 是一个强大的 Python 数据分析库&#xff0c;提供了大量用于数据处理和分析的功能。以下是一些 Pandas 库中常用的功能&#xff1a; 数据创建和操作 Series 和 DataFrame&#xff1a;创建一维的 Series 和二维的 DataFrame 对象。数据导入&#xff1a;从 CSV、Excel、…...

R语言的并发编程

R语言的并发编程 引言 在现代计算中&#xff0c;如何有效地利用计算资源进行数据处理和分析已成为一个重要的研究方向。尤其在大数据时代&#xff0c;数据量的急剧增加让单线程处理方式显得力不从心。为了解决这一问题&#xff0c;各种编程语言都开展了并发编程的研究和应用。…...

STM32 FreeRTOS中断管理

目录 FreeRTOS的中断管理 1、STM32中断优先级管理 2、FreeRTOS任务优先级管理 3、寄存器和内存映射寄存器 4、BASEPRI寄存器 5、FreeRTOS与STM32中断管理结合使用 vPortRaiseBASEPRI vPortSetBASEPRI 6、FromISR后缀 7、在中断服务函数中调用FreeRTOS的API函数需注意 F…...

数据结构-栈和队列

文章目录 一、栈1.概念与结构2.数组栈的实现2.1 栈的结构定义2.2 栈的初始化2.3 栈的销毁2.4 栈的判空2.5 栈的入栈2.6 栈的出栈2.7 查看栈顶元素2.8 栈的大小 3.两种栈的图示结构 二、队列1.概念与结构2.链式队列的实现2.1 队列的结构定义2.2 队列的初始化2.3 队列的销毁2.4 队…...

RabbitMQ---TTL与死信

&#xff08;一&#xff09;TTL 1.TTL概念 TTL又叫过期时间 RabbitMQ可以对队列和消息设置TTL&#xff0c;当消息到达过期时间还没有被消费时就会自动删除 注&#xff1a;这里我们说的对队列设置TTL,是对队列上的消息设置TTL并不是对队列本身&#xff0c;不是说队列过期时间…...

第4章 Kafka核心API——Kafka客户端操作

Kafka客户端操作 一. 客户端操作1. AdminClient API 一. 客户端操作 1. AdminClient API...

Python爬虫学习前传 —— Python从安装到学会一站式服务

早上好啊&#xff0c;大佬们。我们的python基础内容的这一篇终于写好了&#xff0c;啪唧啪唧啪唧…… 说实话&#xff0c;这一篇确实写了很久&#xff0c;一方面是在忙其他几个专栏的内容&#xff0c;再加上生活学业上的事儿&#xff0c;确实精力有限&#xff0c;另一方面&…...

Lora理解QLoRA

Parameter-Efficient Fine-Tuning (PEFT) &#xff1a;节约开销的做法&#xff0c;fine-tune少量参数&#xff0c;而不是整个模型&#xff1b; Low-Rank Adaptation (LoRA) &#xff1a;是PEFT的一种&#xff1b;冻结原参数矩阵&#xff0c;只更新2个小参数矩阵。 原文经过对比…...

网络编程(Modbus进阶)

思维导图 Modbus RTU&#xff08;先学一点理论&#xff09; 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议&#xff0c;由 Modicon 公司&#xff08;现施耐德电气&#xff09;于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能&#xff0c;包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例&#xff1a;使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例&#xff1a;使用OpenAI GPT-3进…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...

git: early EOF

macOS报错&#xff1a; Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...

es6+和css3新增的特性有哪些

一&#xff1a;ECMAScript 新特性&#xff08;ES6&#xff09; ES6 (2015) - 革命性更新 1&#xff0c;记住的方法&#xff0c;从一个方法里面用到了哪些技术 1&#xff0c;let /const块级作用域声明2&#xff0c;**默认参数**&#xff1a;函数参数可以设置默认值。3&#x…...