在 Spring Boot 中实现服务器端推送(SSE):两种方法的比较与实践

news2025/4/19 7:06:08

在现代 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:代码更简洁,利用 FluxMono 提供了更强大的功能。

五、总结

在 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

如果你有任何问题或建议,请随时在评论区留言,我会尽快回复。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2336727.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2025年十六届蓝桥杯Python B组原题及代码解析

相关试题可以在洛谷上测试用例&#xff1a; 2025 十六届 蓝桥杯 Python B组 试题 A&#xff1a;攻击次数 答案&#xff1a;103 print(103)代码&#xff1a; # 初始化敌人的血量 x 2025# 初始化回合数 turn 0# 模拟攻击过程 while x > 0:# 回合数加一turn 1# 第一个英…

数据清洗到底在清洗什么?

在大数据时代&#xff0c;数据是每个企业的五星资产&#xff0c;被誉为“新石油”&#xff0c;但未经处理的数据往往参杂着大量“杂质”。这些“脏数据”不仅影响分析结果&#xff0c;严重的甚至误导企业决策。数据清洗作为数据预处理的关键环节&#xff0c;正是通过“去芜存菁…

Microsoft Azure 基础知识简介

Microsoft Azure 基础知识简介 已完成100 XP 2 分钟 Microsoft Azure 是一个云计算平台&#xff0c;提供一系列不断扩展的服务&#xff0c;可帮助你构建解决方案来满足业务目标。 Azure 服务支持从简单到复杂的一切内容。 Azure 具有简单的 Web 服务&#xff0c;用于在云中托…

数据库ALGORITHM = INSTANT研究过程

背景 偶然在团队中发现同事大量使用 ALGORITHM INSTANT 更新字段&#xff0c;根据固有的理解&#xff0c;平时字段的更新必然会涉及到表结构的更改&#xff0c;印象中数据库会加入MDL锁去保证表数据的一致性。 但是听说在Mysql8.0特性中&#xff0c;表明在更新字段的时候此方法…

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流量数据通常包括用户的访问时间、停留时间、点击行为、页面跳转路径等信息。这些数据分散在不同的服务器日志、数据库或第三方数据平台中&#xff0c;需要通过有效的技术手段进行整合和分析。Python在数据科学领域的广泛应用&#xff0c;得益于其简洁的语法、强大…

【Linux 并发与竞争实验】

【Linux 并发与竞争实验】 之前学习了四种常用的处理并发和竞争的机制&#xff1a;原子操作、自旋锁、信号量和互斥体。本章我们就通过四个实验来学习如何在驱动中使用这四种机制。 文章目录 【Linux 并发与竞争实验】1.原子操作实验1.1 实验程序编写1.2 运行测试 2.自旋锁实验…

wx219基于ssm+vue+uniapp的教师管理系统小程序

开发语言&#xff1a;Java框架&#xff1a;ssmuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;M…

leetcode0079. 单词搜索-medium

1 题目&#xff1a; 单词搜索 官方标定难度&#xff1a;中 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通过相邻的单元格内的字…

SvelteKit 最新中文文档教程(20)—— 最佳实践之性能

前言 Svelte&#xff0c;一个语法简洁、入门容易&#xff0c;面向未来的前端框架。 从 Svelte 诞生之初&#xff0c;就备受开发者的喜爱&#xff0c;根据统计&#xff0c;从 2019 年到 2024 年&#xff0c;连续 6 年一直是开发者最感兴趣的前端框架 No.1&#xff1a; Svelte …

在多系统环境中实现授权闭环,Tetra Pak 借助CodeMeter打造食品工业的安全自动化体系

一、 行业背景与安全新挑战 在食品加工自动化不断深化的背景下&#xff0c;食品安全、功能安全与知识产权保护的需求日益迫切。Tetra Pak 作为全球领先的食品加工和包装解决方案提供商&#xff0c;业务遍布 160 多个国家&#xff0c;涵盖从配料混合、碳酸化处理到全线自动包装。…

B端可视化方案,如何助力企业精准决策,抢占市场先机

在当今竞争激烈的商业环境中&#xff0c;企业需要快速、准确地做出决策以抢占市场先机。B端可视化方案通过将复杂的企业数据转化为直观的图表和仪表盘&#xff0c;帮助企业管理层和业务人员快速理解数据背后的业务逻辑&#xff0c;从而做出精准决策。本文将深入探讨B端可视化方…

0701表单组件-react-仿低代码平台项目

文章目录 1 react表单组件1.1 受控组件 (Controlled Components)示例代码&#xff1a; 1.2 非受控组件 (Uncontrolled Components)示例代码&#xff1a; 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进行操作&#xff0c;实现一些动画的效果&#xff0c;实际就是采样的动画 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 格…

矩阵基础+矩阵转置+矩阵乘法+行列式与逆矩阵

GPU渲染过程 矩阵 什么是矩阵&#xff08;Matrix&#xff09; 向量 &#xff08;3&#xff0c;9&#xff0c;88&#xff09; 点乘&#xff1a;计算向量夹角 叉乘&#xff1a;计算两个向量构成平面的法向量。 矩阵 矩阵有3行&#xff0c;2列&#xff0c;所以表示为M32 获取固…

(EtherCAT 转 EtherNet/IP)EtherCAT/Ethernet/IP/Profinet/ModbusTCP协议互转工业串口网关

型号 协议转换通信网关 EtherCAT 转 EtherNet/IP MS-GW12 概述 MS-GW12 是 EtherCAT 和 EtherNet/IP 协议转换网关&#xff0c;为用户提供两种不同通讯协议的 PLC 进行数据交互的解决方案&#xff0c;可以轻松容易将 EtherNet/IP 网络接入 EtherCAT 网络中&#xff0c;方便…

分享:批量提取图片文字并自动命名文件,ocr识别图片指定区域并重命名文件名工具,基于WPF和腾讯OCR识别的接口的视线方案

一、项目背景 在处理大量图片时,常常需要从图片中提取特定区域的文字信息,并依据这些信息对图片进行重命名。例如,在档案管理领域,大量纸质文件被扫描成图片后,需要从图片中提取关键信息(如文件编号、日期等)来重命名图片,以便后续的检索和管理;在电商领域,商家可能…

Mysql读写分离(1)-服务器的设置(主从复制)

1.简介 随着网站访问和请求量的增加&#xff0c;单台数据库服务器的连接已耗尽&#xff0c;会出现连接请求还在等待&#xff0c;或是数据库服务器崩溃等现象&#xff0c;这时候我们考虑如何减少数据库的连接&#xff0c;可以通过优化代码、使用缓存、数据库读写分离等方式解决…