在 Spring Boot 中实现服务器端推送(SSE):两种方法的比较与实践
在现代 Web 应用中,实时数据推送是一个常见的需求。无论是实时消息通知、股票行情更新,还是在线游戏的实时数据交互,服务器端推送(Server-Sent Events,简称 SSE)都是一种高效且易于实现的解决方案。在 Spring Boot 中,有两种主要方式可以实现 SSE:使用 SseEmitter 和使用 Spring WebFlux。本文将详细介绍这两种方法的实现步骤,并比较它们的优缺点,帮助你在实际开发中选择合适的技术方案。
一、什么是 Server-Sent Events(SSE)
Server-Sent Events 是一种允许服务器向客户端推送实时更新的技术。与传统的轮询或长轮询相比,SSE 提供了一种更高效、更轻量级的解决方案。SSE 使用 HTTP 协议,客户端通过一个简单的 EventSource 接口订阅服务器端的事件流,服务器端则通过持续的 HTTP 连接向客户端发送数据。
SSE 的主要特点包括:
- 单向通信:数据从服务器流向客户端。
- 轻量级:基于 HTTP,不需要额外的 WebSocket 协议支持。
- 自动重连:客户端在连接断开后会自动尝试重新连接。
- 跨浏览器支持:现代浏览器普遍支持 SSE。
二、使用 SseEmitter 实现 SSE
SseEmitter 是 Spring 提供的一个工具类,用于实现 SSE。它允许你手动管理每个客户端的连接,并向它们推送数据。
1. 添加依赖
确保你的 Spring Boot 项目中包含以下依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
2. 创建控制器
创建一个控制器来管理 SSE 连接和推送消息:
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.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;@RestController
public class SSEController {private final Map<String, SseEmitter> emitters = Collections.synchronizedMap(new HashMap<>());@GetMapping("/sse/connect/{clientId}")public SseEmitter connect(@PathVariable String clientId) {SseEmitter emitter = new SseEmitter();emitters.put(clientId, emitter);emitter.onCompletion(() -> emitters.remove(clientId));emitter.onTimeout(() -> emitters.remove(clientId));emitter.onError(e -> emitters.remove(clientId));return emitter;}@GetMapping("/sse/send/{clientId}")public void sendMessage(@PathVariable String clientId) {SseEmitter emitter = emitters.get(clientId);if (emitter != null) {try {emitter.send(SseEmitter.event().data("Hello, client " + clientId + "!"));} catch (IOException e) {emitter.completeWithError(e);}}}
}
3. 前端实现
在前端页面中,使用 EventSource 来订阅 SSE:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>SSE Example</title>
</head>
<body>
<div id="messages"></div>
<script>const eventSource = new EventSource('/sse/connect/client1');eventSource.onmessage = function(event) {const messagesDiv = document.getElementById('messages');const newMessage = document.createElement('p');newMessage.textContent = event.data;messagesDiv.appendChild(newMessage);};eventSource.onerror = function(err) {console.error("Error:", err);eventSource.close();};
</script>
</body>
</html>
三、使用 Spring WebFlux 实现 SSE
Spring WebFlux 提供了更简洁的方式来实现 SSE,利用响应式编程模型。
1. 添加依赖
确保你的项目中包含 WebFlux 依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
2. 创建控制器
使用 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;
import java.time.LocalTime;@RestController
public class FluxController {@GetMapping(value = "/stream/time", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<String> streamTime() {return Flux.interval(Duration.ofSeconds(1)).map(sequence -> "Current Time: " + LocalTime.now());}
}
3. 前端实现
前端代码与使用 SseEmitter 的实现类似,使用 EventSource 来订阅数据流:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>SSE Time Stream</title>
</head>
<body>
<h1>实时推送当前时间</h1>
<ul id="time-list"></ul>
<script>const eventSource = new EventSource('/stream/time');eventSource.onmessage = function(event) {const timeList = document.getElementById('time-list');const listItem = document.createElement('li');listItem.textContent = event.data;timeList.appendChild(listItem);};eventSource.onerror = function(error) {console.error('Error:', error);eventSource.close();};
</script>
</body>
</html>
四、两种方法的比较
1. 灵活性
SseEmitter:提供了更高的灵活性,允许你手动管理每个客户端的连接,适合需要对每个客户端进行精细控制的场景。- Spring WebFlux:更适合生成连续的数据流,代码更简洁,适合响应式编程场景。
2. 性能
SseEmitter:基于传统的 Spring MVC,适合处理少量客户端连接。- Spring WebFlux:基于响应式编程模型,适合处理大量并发连接,性能更高。
3. 易用性
SseEmitter:代码相对复杂,需要手动管理连接和错误处理。- Spring WebFlux:代码更简洁,利用
Flux和Mono提供了更强大的功能。
五、总结
在 Spring Boot 中实现 SSE 有多种方式,选择哪种方式取决于你的具体需求。如果你需要对每个客户端进行精细控制,SseEmitter 是一个不错的选择。如果你需要处理大量并发连接,或者希望代码更简洁,Spring WebFlux 是一个更好的选择。
希望本文能帮助你在实际开发中更好地实现 SSE,为你的应用带来更实时、更高效的用户体验。
参考资料
- 如何使用Spring Boot Webflux优雅实现数据流的SSE推送?
- Spring boot还在使用websocket推数据?快来试试SSE吧
- Spring Boot 整合 SSE(Server-Sent Events) - CSDN博客
- Spring 中 Server-Sent Events(SSE)消息推送实现
- SpringBoot + SSE 实时异步流式推送
- Spring Boot + SSE 打造实时消息推送 | SSN
如果你有任何问题或建议,请随时在评论区留言,我会尽快回复。
相关文章:
在 Spring Boot 中实现服务器端推送(SSE):两种方法的比较与实践
在现代 Web 应用中,实时数据推送是一个常见的需求。无论是实时消息通知、股票行情更新,还是在线游戏的实时数据交互,服务器端推送(Server-Sent Events,简称 SSE)都是一种高效且易于实现的解决方案。在 Spri…...
2025年十六届蓝桥杯Python B组原题及代码解析
相关试题可以在洛谷上测试用例: 2025 十六届 蓝桥杯 Python B组 试题 A:攻击次数 答案:103 print(103)代码: # 初始化敌人的血量 x 2025# 初始化回合数 turn 0# 模拟攻击过程 while x > 0:# 回合数加一turn 1# 第一个英…...
数据清洗到底在清洗什么?
在大数据时代,数据是每个企业的五星资产,被誉为“新石油”,但未经处理的数据往往参杂着大量“杂质”。这些“脏数据”不仅影响分析结果,严重的甚至误导企业决策。数据清洗作为数据预处理的关键环节,正是通过“去芜存菁…...
Microsoft Azure 基础知识简介
Microsoft Azure 基础知识简介 已完成100 XP 2 分钟 Microsoft Azure 是一个云计算平台,提供一系列不断扩展的服务,可帮助你构建解决方案来满足业务目标。 Azure 服务支持从简单到复杂的一切内容。 Azure 具有简单的 Web 服务,用于在云中托…...
mysql表类型查询
普通表 SELECT table_schema AS database_name,table_name FROM information_schema.tables WHERE table_schema NOT IN (information_schema, mysql, performance_schema, sys)AND table_type BASE TABLEAND table_name NOT IN (SELECT DISTINCT table_name FROM informatio…...
数据库ALGORITHM = INSTANT研究过程
背景 偶然在团队中发现同事大量使用 ALGORITHM INSTANT 更新字段,根据固有的理解,平时字段的更新必然会涉及到表结构的更改,印象中数据库会加入MDL锁去保证表数据的一致性。 但是听说在Mysql8.0特性中,表明在更新字段的时候此方法…...
n8n 为技术团队打造的安全工作流自动化平台
AI MCP 系列 AgentGPT-01-入门介绍 Browser-use 是连接你的AI代理与浏览器的最简单方式 AI MCP(大模型上下文)-01-入门介绍 AI MCP(大模型上下文)-02-awesome-mcp-servers 精选的 MCP 服务器 AI MCP(大模型上下文)-03-open webui 介绍 是一个可扩展、功能丰富且用户友好的…...
基于Python的App流量大数据分析与可视化方案
一、引言 App流量数据通常包括用户的访问时间、停留时间、点击行为、页面跳转路径等信息。这些数据分散在不同的服务器日志、数据库或第三方数据平台中,需要通过有效的技术手段进行整合和分析。Python在数据科学领域的广泛应用,得益于其简洁的语法、强大…...
【Linux 并发与竞争实验】
【Linux 并发与竞争实验】 之前学习了四种常用的处理并发和竞争的机制:原子操作、自旋锁、信号量和互斥体。本章我们就通过四个实验来学习如何在驱动中使用这四种机制。 文章目录 【Linux 并发与竞争实验】1.原子操作实验1.1 实验程序编写1.2 运行测试 2.自旋锁实验…...
wx219基于ssm+vue+uniapp的教师管理系统小程序
开发语言:Java框架:ssmuniappJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:M…...
leetcode0079. 单词搜索-medium
1 题目: 单词搜索 官方标定难度:中 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。 单词必须按照字母顺序,通过相邻的单元格内的字…...
SvelteKit 最新中文文档教程(20)—— 最佳实践之性能
前言 Svelte,一个语法简洁、入门容易,面向未来的前端框架。 从 Svelte 诞生之初,就备受开发者的喜爱,根据统计,从 2019 年到 2024 年,连续 6 年一直是开发者最感兴趣的前端框架 No.1: Svelte …...
在多系统环境中实现授权闭环,Tetra Pak 借助CodeMeter打造食品工业的安全自动化体系
一、 行业背景与安全新挑战 在食品加工自动化不断深化的背景下,食品安全、功能安全与知识产权保护的需求日益迫切。Tetra Pak 作为全球领先的食品加工和包装解决方案提供商,业务遍布 160 多个国家,涵盖从配料混合、碳酸化处理到全线自动包装。…...
复数概念的演进 3 —— 复数的意义
注:本文为 “从三次方程到复平面:复数概念的演进” 相关文章合辑。 因 csdn 篇幅限制分篇连载,此为第 3 篇。 生料合辑,同主题文章未整理去重。 机翻,未校。 Complex number and its discovery history 复数及其发…...
三菱PLC
三菱PLC通信协议及读写 引言 三菱PLC(Programmable Logic Controller,可编程逻辑控制器)是工业自动化领域中广泛使用的一款PLC品牌。三菱PLC支持多种通信协议,包括Modbus、Ethernet/IP、Melsec Net等。本文将详细介绍三菱PLC的通…...
B端可视化方案,如何助力企业精准决策,抢占市场先机
在当今竞争激烈的商业环境中,企业需要快速、准确地做出决策以抢占市场先机。B端可视化方案通过将复杂的企业数据转化为直观的图表和仪表盘,帮助企业管理层和业务人员快速理解数据背后的业务逻辑,从而做出精准决策。本文将深入探讨B端可视化方…...
0701表单组件-react-仿低代码平台项目
文章目录 1 react表单组件1.1 受控组件 (Controlled Components)示例代码: 1.2 非受控组件 (Uncontrolled Components)示例代码: 2 AntD表单组件实战2.1 开发搜索功能2.2 开发注册页2.3 开发登录页2.4 表单组件校验 结语 1 react表单组件 input表单组件…...
【adb】bat批处理+adb 自动亮屏,自动解锁屏幕,启动王者荣耀
准备adb 下载 需要确认是否安装了adb.exe文件,可以在: 任务管理器 -->详细信息–>找一下后台运行的adb 安装过anroid模拟器,也存在adb,例如:雷电安装目录 D:\leidian\LDPlayer9 单独下载adb 官方下载地址:[官方网址] 下载目录文件: 测试adb USB连接手机 首先在设置界…...
Distortion, Animation Raymarching
这节课的主要目的是对uv进行操作,实现一些动画的效果,实际就是采样的动画 struct texDistort {float2 texScale(float2 uv, float2 scale){float2 texScale (uv - 0.5) * scale 0.5;return texScale;}float2 texRotate(float2 uv, float angle){float…...
SpringBoot整合POI实现Excel文件的导出与导入
使用 Apache POI 操作 Excel文件,系列文章: 《SpringBoot整合POI实现Excel文件的导出与导入》 《SpringMVC实现文件的上传与下载》 《C#使用NPOI导出Excel文件》 《NPOI使用手册》 1、Apache POI 的介绍 Apache POI 是一个基于 Java 的开源库,专为读写 Microsoft Office 格…...
LeetCode 2537.统计好子数组的数目:滑动窗口(双指针)
【LetMeFly】2537.统计好子数组的数目:滑动窗口(双指针) 力扣题目链接:https://leetcode.cn/problems/count-the-number-of-good-subarrays/ 给你一个整数数组 nums 和一个整数 k ,请你返回 nums 中 好 子数组的数目。 一个子数组 arr 如果…...
矩阵基础+矩阵转置+矩阵乘法+行列式与逆矩阵
GPU渲染过程 矩阵 什么是矩阵(Matrix) 向量 (3,9,88) 点乘:计算向量夹角 叉乘:计算两个向量构成平面的法向量。 矩阵 矩阵有3行,2列,所以表示为M32 获取固…...
(EtherCAT 转 EtherNet/IP)EtherCAT/Ethernet/IP/Profinet/ModbusTCP协议互转工业串口网关
型号 协议转换通信网关 EtherCAT 转 EtherNet/IP MS-GW12 概述 MS-GW12 是 EtherCAT 和 EtherNet/IP 协议转换网关,为用户提供两种不同通讯协议的 PLC 进行数据交互的解决方案,可以轻松容易将 EtherNet/IP 网络接入 EtherCAT 网络中,方便…...
分享:批量提取图片文字并自动命名文件,ocr识别图片指定区域并重命名文件名工具,基于WPF和腾讯OCR识别的接口的视线方案
一、项目背景 在处理大量图片时,常常需要从图片中提取特定区域的文字信息,并依据这些信息对图片进行重命名。例如,在档案管理领域,大量纸质文件被扫描成图片后,需要从图片中提取关键信息(如文件编号、日期等)来重命名图片,以便后续的检索和管理;在电商领域,商家可能…...
Mysql读写分离(1)-服务器的设置(主从复制)
1.简介 随着网站访问和请求量的增加,单台数据库服务器的连接已耗尽,会出现连接请求还在等待,或是数据库服务器崩溃等现象,这时候我们考虑如何减少数据库的连接,可以通过优化代码、使用缓存、数据库读写分离等方式解决…...
STM32F103ZET6移植FATFS文件系统教程(W25Q32)
一、FATFS核心特性 跨平台支持 支持FAT12/FAT16/FAT32格式,兼容Windows文件系统; 采用标准C语言编写,代码量小且支持RTOS。 配置灵活性 通过宏定义实现功能裁剪,例如: FF_FS_READONLY:设为1时禁…...
STM32 模块化开发实战指南:系列介绍
本文是《STM32 模块化开发实战指南》系列的导读篇,旨在介绍整个系列的写作目的、适用读者、技术路径和每一篇的主题规划。适合从事 STM32、裸机或 RTOS 嵌入式开发的个人开发者、初创工程师或企业项目团队。 为什么要写这个系列? 在嵌入式开发中,很多人刚开始都是从点亮一个…...
AF3 create_alignment_db_sharded脚本create_shard函数解读
AlphaFold3 create_alignment_db_sharded 脚本在源代码的scripts/alignment_db_scripts文件夹下。 该脚本中的 create_shard 函数的功能是将一部分链(shard_files)中的所有对齐文件写入一个 .db 文件,并返回这些链的索引信息(字节…...
【Python语言基础】21、Python标准库
文章目录 1. 标准库1.1 标准库构成及特点1.2 常见分类和模块1.3 标准库使用 1. 标准库 Python 标准库就像是 Python 自带的 “百宝箱”,里面装了各种各样已经写好的工具,你在编程的时候可以直接拿来用,不用自己再费劲去编写。 什么是标准库 …...
数据库脱裤
假设你已经getshell 找到mysql账号密码。 网站要连接mysql,就需要把mysql的账号密码保存在一个php文件中,类似config.php、common.inc.php等,在shell中,读取这些文件,找到其中信息即可 下面是一些常见平台的配置文…...
