使用 ResponseBodyEmitter 实现异步响应式数据流处理
1. 概述
1.1 什么是 ResponseBodyEmitter
ResponseBodyEmitter 是 Spring MVC 提供的一个接口,用于支持异步返回响应数据流。它允许在控制器方法中逐步发送数据给客户端,而无需一次性生成完整的响应。
1.2 使用场景
- 实时数据推送(如股票行情、聊天消息等)。
- 大量数据分批传输。
- 服务器发送事件(SSE, Server-Sent Events)。
1.3 优势与局限性
优势:
- 支持异步数据流处理。
- 能够实时更新客户端数据。
- 简化了复杂数据流的管理。
局限性:
- 高并发场景下需要额外优化。
- 客户端断开连接时需手动处理资源释放。
2. 环境准备
2.1 添加依赖
确保项目中包含以下依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
2.2 配置 Spring Boot 项目
创建一个标准的 Spring Boot 项目,并配置好基础环境。
3. 基本使用方法
3.1 创建控制器
定义一个控制器类,用于处理 HTTP 请求。
3.2 返回 ResponseBodyEmitter 对象
通过返回 ResponseBodyEmitter 对象实现异步数据流。
3.3 发送数据给客户端
使用 emitter.send() 方法向客户端发送数据。
示例代码:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;@RestController
@RequestMapping("/stream")
public class StreamController {private final ExecutorService executorService = Executors.newFixedThreadPool(10);@GetMapping("/events")public ResponseBodyEmitter handleEvents() {ResponseBodyEmitter emitter = new ResponseBodyEmitter();// 使用线程池管理异步任务executorService.execute(() -> {try {for (int i = 0; i < 5; i++) {// 模拟延迟TimeUnit.SECONDS.sleep(1);// 发送数据给客户端emitter.send("Event " + i + "\n");}// 完成发送emitter.complete();} catch (IOException | InterruptedException e) {// 发生错误时处理emitter.completeWithError(e);}});return emitter;}
}
说明:
- 使用
ExecutorService管理异步任务,避免直接创建线程。 TimeUnit.SECONDS.sleep(1)模拟每秒发送一次数据。emitter.send("Event " + i + "\n")发送数据给客户端。emitter.complete()完成数据发送。emitter.completeWithError(e)处理异常。
4. 实现服务器发送事件(SSE)
4.1 SSE 简介
SSE 是一种基于 HTTP 的协议,允许服务器向客户端推送实时更新的数据。
4.2 使用 ResponseBodyEmitter 实现 SSE
通过设置响应头 Content-Type: text/event-stream,可以实现 SSE。
示例代码:
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;@RestController
@RequestMapping("/sse")
public class SseController {private final ExecutorService executorService = Executors.newFixedThreadPool(10);@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public SseEmitter handleSse() {SseEmitter emitter = new SseEmitter();// 使用线程池管理异步任务executorService.execute(() -> {try {for (int i = 0; i < 5; i++) {// 模拟延迟TimeUnit.SECONDS.sleep(1);// 发送数据给客户端emitter.send(SseEmitter.event().name("message").data("Event " + i));}// 完成发送emitter.complete();} catch (IOException | InterruptedException e) {// 发生错误时处理emitter.completeWithError(e);}});return emitter;}
}
说明:
- 使用
SseEmitter实现 SSE。 MediaType.TEXT_EVENT_STREAM_VALUE设置响应头为text/event-stream。emitter.send(SseEmitter.event().name("message").data("Event " + i))发送带有名称的数据。emitter.complete()完成数据发送。emitter.completeWithError(e)处理异常。
4.3 客户端代码示例
HTML 示例:
<!DOCTYPE html>
<html>
<head><title>SSE Example</title>
</head>
<body><div id="events"></div><script>const eventSource = new EventSource('/sse/stream');eventSource.onmessage = function(event) {document.getElementById('events').innerHTML += event.data + '<br>';};eventSource.onerror = function(err) {console.error("EventSource failed:", err);};</script>
</body>
</html>
说明:
- 使用
EventSource连接到 SSE 流。 eventSource.onmessage处理接收到的数据。eventSource.onerror处理错误。
5. 异步数据推送的最佳实践
5.1 数据流管理
- 使用线程池管理异步任务,避免资源耗尽。
- 设置合理的超时时间,防止连接长时间占用。
示例代码:
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;import java.io.IOException;
import java.util.concurrent.ExecutorService;
import 相关文章:
使用 ResponseBodyEmitter 实现异步响应式数据流处理
1. 概述 1.1 什么是 ResponseBodyEmitter ResponseBodyEmitter 是 Spring MVC 提供的一个接口,用于支持异步返回响应数据流。它允许在控制器方法中逐步发送数据给客户端,而无需一次性生成完整的响应。 1.2 使用场景 实时数据推送(如股票行情、聊天消息等)。大量数据分批…...
Uniapp项目运行到微信小程序、H5、APP等多个平台教程
摘要:Uniapp作为一款基于Vue.js的跨平台开发框架,支持“一次开发,多端部署”。本文将手把手教你如何将Uniapp项目运行到微信小程序、H5、APP等多个平台,并解析常见问题。 一、环境准备 在开始前,请确保已安装以下工具…...
Ubuntu 下 nginx-1.24.0 源码分析 - cycle->modules[i]->type
Nginx 中主要有以下几种模块类型 类型 含义 NGX_CORE_MODULE 核心模块(如进程管理、错误日志、配置解析)。 NGX_EVENT_MODULE 事件模块(如 epoll、kqueue 等 IO 多路复用机制的实现)。 NGX_HTTP_MODULE HTTP 模块…...
基于SpringBoot的“文物管理系统”的设计与实现(源码+数据库+文档+PPT)
基于SpringBoot的“文物管理系统”的设计与实现(源码数据库文档PPT) 开发语言:Java 数据库:MySQL 技术:SpringBoot 工具:IDEA/Ecilpse、Navicat、Maven 系统展示 系统总体功能模块图 E-R实体图 系统首页界面 系统…...
dify + ollama + deepseek-r1+ stable-diffusion 构建绘画智能体
故事背景 stable-diffusion 集成进 dify 后,我们搭建一个小智能体,验证下文生图功能 业务流程 #mermaid-svg-6nSwwp69eMizP6bt {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-6nSwwp69eMiz…...
Android原生gif动图加载AnimatedImageDrawable
Android原生gif动图加载AnimatedImageDrawable 从Android P(9.0)开始,Android系统支持gif动图的原生控件AnimatedImageDrawable,可以播放加载gif动图。 AnimatedImageDrawable官方文档链接: https://developer.andro…...
Windows 系统 Docker Desktop 入门教程:从零开始掌握容器化技术
文章目录 前言一、Docker 简介二、Docker Desktop 安装2.1 系统要求2.2 安装步骤 三、Docker 基本概念四、Docker 常用命令五、实战:运行你的第一个容器5.1 拉取并运行 Nginx 容器5.2 查看容器日志5.3 停止并删除容器 六、总结 前言 随着云计算和微服务架构的普及&…...
记录小白使用 Cursor 开发第一个微信小程序(二):创建项目、编译、预览、发布(250308)
文章目录 记录小白使用 Cursor 开发第一个微信小程序(二):创建项目、编译、预览、发布(250308)一、创建项目1.1 生成提示词1.2 生成代码 二、编译预览2.1 导入项目2.2 编译预览 三、发布3.1 在微信开发者工具进行上传3…...
实战 - 使用 AutoAWQ 进行量化
文章目录 一、准备1、安装 autoawq2、模型准备 二、量化config.json 文件变化 三、加载量化后模型量化后的输出原始输出对比 四、查看模型的精度1、查看模型卡2、查看 config.json 中的 torch_dtype3、打印模型信息4、model.dtype 未必是模型精度 一、准备 1、安装 autoawq p…...
C++20 格式化库:强大的字符串格式化工具
文章目录 格式化语法常见用法1. 填充和对齐2. 数值格式化3. 进制格式化4. 自定义类型 示例代码注意事项 C20 的格式化库是一个强大的工具,用于处理字符串的格式化操作。它提供了类似于 Python 中 str.format() 的功能,但语法和用法更符合 C 的风格。以下…...
【一文学会 HTML5】
目录 HTML概述基本概念HTML 发展历程HTML 基本结构 网页基本标签标题标签(<h1> - <h6>)段落标签(<p>)换行标签(<br>)水平线标签(<hr>)注释࿰…...
如何在WPS中接入DeepSeek并使用OfficeAI助手(超细!成功版本)
目录 第一步:下载并安装OfficeAI助手 第二步:申请API Key 第三步:两种方式导入WPS 第一种:本地大模型Ollama 第二种APIKey接入 第四步:探索OfficeAI的创作功能 工作进展汇报 PPT大纲设计 第五步:我的使用体验(体验建议) …...
蓝耘智算 + 通义万相 2.1:为 AIGC 装上 “智能翅膀”,翱翔创作新天空
1. 引言:AIGC 的崛起与挑战 在过去几年中,人工智能生成内容(AIGC)技术突飞猛进。AIGC 涉及了文本生成、图像创作、音乐创作、视频制作等多个领域,并逐渐渗透到日常生活的方方面面。传统的内容创作方式已经被许多人类创…...
电脑如何在系统默认的壁纸中切换自己喜欢的
1、声明:该切换壁纸仅支持win10。 当你想去切换系统默认的壁纸,但是不知道该怎么切换,别慌,小亦教你几招帮你快速切换自定义壁纸。 我们平常使用的win10桌面壁纸大部分都是 简单、朴素的壁纸,但如果你想要切换自己喜…...
【大模型安全】安全解决方案
【大模型安全】安全解决方案 1.技术层面2.数据层面数据收集阶段训练阶段模型推理阶段 1.技术层面 在使用大语言模型时,通常有几种选择:一种是采用封装好的大语言模型SaaS云服务;另一种是在公有云上部署自有的大语言模型,并通过权…...
Windows编译环境搭建(MSYS2\MinGW\cmake)
我的音视频/流媒体开源项目(github) 一、基础环境搭建 1.1 MSYS2\MinGW 参考:1. 基于MSYS2的Mingw-w64 GCC搭建Windows下C开发环境_msys2使用mingw64编译 在Widndows系统上,使用gcc工具链(g)进行C程序开发?可以的&a…...
云曦春季开学考复现(2025)
Crypto 划水的dp和dq 下载附件后是简单的RSA算法题,之所以说简单是因为给了公钥e 趁热打铁,昨天刚学的RSA,既然有p有q,也有e,而np*q,可以算出欧拉函数值phi(p-1)*(q-1&…...
股票交易所官方api接口有哪些?获取和使用需要满足什么条件
炒股自动化:申请官方API接口,散户也可以 python炒股自动化(0),申请券商API接口 python炒股自动化(1),量化交易接口区别 Python炒股自动化(2):获取…...
《WebForms 实例》
《WebForms 实例》 引言 WebForms 是微软推出的一种用于构建动态Web应用程序的技术。它基于ASP.NET框架,允许开发者使用服务器端控件来构建用户界面,并通过事件驱动模型来响应用户交互。本文将通过一些实例,详细介绍WebForms的使用方法&…...
【每日学点HarmonyOS Next知识】 状态变量、公共Page、可见区域变化回调、接收参数、拖拽排序控件
1、HarmonyOS 在定时器里面改变state修饰的变量,无法更新UI吗? 将函数function写成了封装函数的形式就可以了 Entry Component struct Index {State acSetValve: number 0;aboutToAppear(): void {setInterval(() > {this.acSetValve 200;console…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...
