当前位置: 首页 > news >正文

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. 运行 & 测试

  1. 启动 Spring Boot 应用.
  2. 访问 http://localhost:8080 (默认端口).
  3. 在输入框中输入消息并点击发送,观察逐字显示的效果.

总结

本文详细介绍了如何使用 Spring WebFlux 和 SSE 实现类似 ChatGPT 的流式回复效果,并提供了完整的代码示例。希望读者能够通过本文掌握该技术,并在实际项目中灵活运用。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 施工窝工停工计算及索赔要点汇总
  • <数据集>集装箱缺陷识别数据集<目标检测>
  • 【MySQL】用户管理——用户、用户信息、创建用户、删除用户、修改用户密码、数据库的权限、给用户权限、回收权限
  • 0001 与会计的渊源
  • Canvas:二次贝塞曲线
  • 15.2 Scikit-learn简介与常用模型
  • 树莓派4b无法选择声音输入输出设备问题
  • ContentProvider:在Android中实现进程间数据共享
  • unity2107,导入spine骨骼动画报错
  • 8.4.数据库基础技术-SQL
  • Java后端面试题
  • Lua脚本 快速掌握
  • 华为设备的两种配置生效模式
  • 深度学习 —— 个人学习笔记20(转置卷积、全卷积网络)
  • 【大数据】6:MapReduce YARN 初体验
  • 【162天】黑马程序员27天视频学习笔记【Day02-上】
  • 【391天】每日项目总结系列128(2018.03.03)
  • 【399天】跃迁之路——程序员高效学习方法论探索系列(实验阶段156-2018.03.11)...
  • fetch 从初识到应用
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • STAR法则
  • Synchronized 关键字使用、底层原理、JDK1.6 之后的底层优化以及 和ReenTrantLock 的对比...
  • Vue 重置组件到初始状态
  • 创建一个Struts2项目maven 方式
  • 两列自适应布局方案整理
  • 每天一个设计模式之命令模式
  • 如何正确配置 Ubuntu 14.04 服务器?
  • 深入浏览器事件循环的本质
  • 我与Jetbrains的这些年
  • 无服务器化是企业 IT 架构的未来吗?
  • 新版博客前端前瞻
  • 转载:[译] 内容加速黑科技趣谈
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • 整理一些计算机基础知识!
  • ​一文看懂数据清洗:缺失值、异常值和重复值的处理
  • #pragam once 和 #ifndef 预编译头
  • #pragma预处理命令
  • $.ajax()参数及用法
  • (13)Hive调优——动态分区导致的小文件问题
  • (33)STM32——485实验笔记
  • (C++二叉树05) 合并二叉树 二叉搜索树中的搜索 验证二叉搜索树
  • (ros//EnvironmentVariables)ros环境变量
  • (SERIES12)DM性能优化
  • (附源码)springboot家庭装修管理系统 毕业设计 613205
  • (附源码)ssm教师工作量核算统计系统 毕业设计 162307
  • (附源码)计算机毕业设计SSM教师教学质量评价系统
  • (每日持续更新)jdk api之FileReader基础、应用、实战
  • (免费分享)基于springboot,vue疗养中心管理系统
  • (十) 初识 Docker file
  • (十二)springboot实战——SSE服务推送事件案例实现
  • (实测可用)(3)Git的使用——RT Thread Stdio添加的软件包,github与gitee冲突造成无法上传文件到gitee
  • (循环依赖问题)学习spring的第九天
  • (原)记一次CentOS7 磁盘空间大小异常的解决过程
  • (杂交版)植物大战僵尸
  • (转) 深度模型优化性能 调参