Spring WebFlux 实现 SSE 流式回复:类GPT逐字显示回复效果完整指南
本节将提供基于 Spring WebFlux 和 SSE 实现类ChatGPT流式回复效果的完整代码示例,并详细说明所需的依赖和配置。
1. 项目配置
- 构建工具: Maven 或 Gradle
- 依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
2. 后端代码 (Spring WebFlux)
package com.example.ssedemo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import org.springframework.http.codec.ServerSentEvent;import java.time.Duration;@SpringBootApplication
@RestController
public class SseDemoApplication {public static void main(String[] args) {SpringApplication.run(SseDemoApplication.class, args);}@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<ServerSentEvent<String>> streamChatGPTReply(@RequestParam String message) {// 模拟调用 ChatGPT API 获取回复String reply = "收到消息: " + message + ". 正在思考...";return Flux.<String>create(sink -> {sink.next(reply); // 先发送初始回复// 模拟逐字生成回复for (int i = 0; i < reply.length(); i++) {try {Thread.sleep(100); // 模拟延迟sink.next(reply.substring(0, i + 1));} catch (InterruptedException e) {throw new RuntimeException(e);}}sink.complete();}).map(data -> ServerSentEvent.<String>builder().data(data).build()).delayElements(Duration.ofMillis(100)); // 每隔一段时间发送一个字符}
}
另外一种方式:
private final WebClient webClient; // 用于调用外部 APIpublic ChatController(WebClient.Builder webClientBuilder) {this.webClient = webClientBuilder.baseUrl("http://api.example.com").build();
}@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<String>> streamChatGPTReply(@RequestParam String message) {// 使用 WebClient 异步调用外部 APIreturn webClient.post().uri("/api/external") .bodyValue(message).retrieve().bodyToFlux(String.class) // 假设 API 返回 String 类型数据.map(data -> ServerSentEvent.<String>builder().data(data) // 将 API 响应数据包装到 SSE 事件中.build()).delayElements(Duration.ofMillis(100));
}
3. 前端代码 (HTML & JavaScript)
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>SSE Demo</title>
</head>
<body><h1>SSE Chat Demo</h1><div id="output"></div><input type="text" id="message"><button onclick="sendMessage()">发送</button><script>const output = document.getElementById('output');function sendMessage() {const message = document.getElementById('message').value;const eventSource = new EventSource('/stream?message=' + message);eventSource.onmessage = (event) => {output.innerHTML += event.data + '<br>';};eventSource.onerror = (error) => {console.error('SSE 连接错误:', error);eventSource.close();};}</script>
</body>
</html>
4. 代码解析
- 后端:
@GetMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE): 指定响应类型为text/event-stream,这是 SSE 的标准 MIME 类型。Flux<ServerSentEvent<String>>: 使用 Spring WebFlux 的Flux类型返回数据流,并使用ServerSentEvent包装每个数据项.sink.next(): 向数据流中发送数据。sink.complete(): 通知数据流结束。
- 前端:
new EventSource('/stream'): 创建 EventSource 对象,连接到后端 SSE 接口.eventSource.onmessage: 监听message事件,接收后端推送的数据.eventSource.onerror: 监听连接错误.
5. 运行 & 测试
- 启动 Spring Boot 应用.
- 访问
http://localhost:8080(默认端口). - 在输入框中输入消息并点击发送,观察逐字显示的效果.
总结
本文详细介绍了如何使用 Spring WebFlux 和 SSE 实现类似 ChatGPT 的流式回复效果,并提供了完整的代码示例。希望读者能够通过本文掌握该技术,并在实际项目中灵活运用。
相关文章:
Spring WebFlux 实现 SSE 流式回复:类GPT逐字显示回复效果完整指南
本节将提供基于 Spring WebFlux 和 SSE 实现类ChatGPT流式回复效果的完整代码示例,并详细说明所需的依赖和配置。 1. 项目配置 构建工具: Maven 或 Gradle依赖: <dependency><groupId>org.springframework.boot</groupId><artifactId>sp…...
成功解决7版本的数据库导入 8版本数据库脚本报错问题
我 | 在这里 ⭐ 全栈开发攻城狮、全网10W粉丝、2022博客之星后端领域Top1、专家博主。 🎓擅长 指导毕设 | 论文指导 | 系统开发 | 毕业答辩 | 系统讲解等。已指导60位同学顺利毕业 ✈️个人公众号:热爱技术的小郑。回复 Java全套视频教程 或 前端全套视频…...
如何让RStudio使用不同版本的R
下面内容摘录自: 专栏问答:管理和选择不同的R,如何做好R的笔记_rstudio如何在不同的r版本中进行切换-CSDN博客 欢迎订阅我们专栏 问题一:如何发现RStudio需要安装和使用不同版本的R。这是为什么呢? R允许用户在同一系统…...
汽车免拆诊断案例 | 2011 款进口现代新胜达车智能钥匙系统有时失效
故障现象 一辆2011款进口现代新胜达车,搭载G4KE发动机,累计行驶里程约为26.3万km。车主进厂反映,有时进入车内按下起动按钮,发动机无法起动,且组合仪表黑屏。 故障诊断 接车后试车,车辆使用一切正常。…...
Count clock
写了半天不对,才注意到是十六进制的 - - 另外安装了vivado 哈哈哈哈,可以看看写的到底对不对 之前好多程序在 hdlbits 可以正确运行 但是 vivado 编译不通过。 module clock(input clk,input reset,input ena,output reg pm,output reg[7:0] hh,output …...
【MySQL】1.MySQL基本操作
目录 一、MySQL数据库登陆 1、设置环境变量 2、cmd命令登陆数据库 二、基本操作语法 1、显示数据库——SHOW 2、使用/选择数据库——USE 3、删除——DROP 4、创建——CREATE 5、查看表结构——DESC 6、数据操作——增删改查 (1)增/插入&#…...
Qt .qm文件详解
Qt中的.qm文件是Qt翻译文件的一种,主要用于支持软件的多语言转换。在生成Qt应用程序时,qm文件会被包含进应用程序中,根据逻辑以显示对应语言的界面。 .qm文件的基本信息 格式:.qm文件是Qt应用程序中用于存储翻译文本的二进制文件…...
【计算机网络】UDP实战
其实经过这几天写的几种不同的UDP的简易客户端与服务端,还是很有套路的,起手式都是非常像的。 更多的难点对我来说反而是解耦,各种各样的function一用,回调函数一调,呕吼,就会懵一下。 对于这篇文章&#x…...
七、ESP32-S3上使用MicroPython点亮WS2812智能LED灯珠并通过web控制和JS颜色选择器改变灯珠颜色
本地代码集成离线iro.js库来添加一个颜色选择器控件,在无网络环境可以通过JavaScript将选中的颜色发送到服务器以改变LED颜色。以下是将iro.js集成到网页后的颜色图片。 Iro.js 地址API操作手册 color:change # 每当所选颜色发生变化时触发 - 无论是当用户与颜色选…...
Z 字形遍历二叉树
假设一个二叉树上各结点的权值互不相同。 我们就可以通过其后序遍历和中序遍历来确定唯一二叉树。 请你输出该二叉树的 ZZ 字形遍历序列----也就是说,从根结点开始,逐层遍历,第一层从右到左遍历,第二层从左到右遍历,…...
[Vue]Vue3从入门到精通-综合案例分析
一.Vue是什么: 概念:Vue是一个用于构建用户界面的渐进式的框架 以下的内容是自里向外的 声明式渲染(Vuejs核心包)组件系统(Vuejs核心包)客户端路由VueRouter大规模状态管理Vuex构建工具Webpack/Vite Vue的两种使用方式: Vue核心包开发-&…...
深度学习——神经网络(neural network)详解(二). 带手算步骤,步骤清晰0基础可看
深度学习——神经网络(neural network)详解(二). 手算步骤,步骤清晰0基础可看 前文如下:深度学习——神经网络(neural network)详解(一). 带手算步骤&#x…...
【扒网络架构】backbone、ccff
backbone CCFF 还不知道网络连接方式,只是知道了每一层 backbone backbone.backbone.conv1.weight torch.Size([64, 3, 7, 7])backbone.backbone.layer1.0.conv1.weight torch.Size([64, 64, 1, 1])backbone.backbone.layer1.0.conv2.weight torch.Size([64, 64,…...
linux进程
exit()函数正常结束进程 man ps aux 是在使用 ps 命令时常用的一个选项组合,用于显示系统中所有进程的详细信息。aux 不是 ps 命令的一个正式选项,而是三个选项的组合:a, u, 和 x。这三个选项分别代表不同的含义&#…...
PRVF-4037 : CRS is not installed on any of the nodes
描述:公司要求替换centos,重新安装ORACLE LINUX RAC的数据库做备库,到时候切换成主库,安装Linux7GRID 19C 11G Oracle,顺利安装grid 19c,安装11G数据库软件的时候检测报如题错误:**PRVF-4037 …...
整理 酷炫 Flutter 开源UI框架 FAB
flutter_villains 灵活且易于使用的页面转换。 项目地址:https://github.com/Norbert515/flutter_villains 项目Demo:https://download.csdn.net/download/qq_36040764/89631324...
Unity 编写自己的aar库,接收Android广播(broadcastReceiver)并传递到Unity
编写本文是因为找了很多文章,都比较片段,不容易理解,对于Android新手来说理解起来不友好。我这里写了一个针对比较小白的文章,希望有所帮助。 Android端 首先还是先来写Android端,我们新建一个Android空项目…...
Mysql cast函数、cast用法、字符串转数字、字符串转日期、数据类型转换
文章目录 一、语法二、示例2.1、复杂示例 三、cast与convert的区别 CAST 函数是 SQL 中的一种类型转换函数,它用于将一个数据类型转换为另一个数据类型,这篇文章主要介绍了Mysql中Cast()函数的用法,需要的朋友可以参考下。 Mysql提供了两种将值转换成指…...
微信小程序开发之组件复用机制
新建复用文件,另外需要注册 behavior 例如: 在behavior.js文件中写入方法,并向外暴露出去 写法一: module.exportsBehavior({data: {num: 1},lifetimes: {created() {console.log(1);}} })写法二: const behavior …...
数据结构--线性表
数据结构分类 集合 线性结构(一对一) 树形结构(一对多) 图结构(多对多) 数据结构三要素 1、逻辑结构 2、数据的运算 3、存储结构(物理结构) 线性表分类 1、顺序表 2、链表 3、栈 4、队列 5、串 线性表--顺序表 顺序表的特点 顺序表的删除和插入…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
快刀集(1): 一刀斩断视频片头广告
一刀流:用一个简单脚本,秒杀视频片头广告,还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农,平时写代码之余看看电影、补补片,是再正常不过的事。 电影嘛,要沉浸,…...
