🏡 博客首页:IT 派同学
⛳️ 欢迎关注 🐳 点赞 🎒 收藏 ✏️ 留言
🎢 本文由 IT 派同学原创编撰
🚧 系列专栏:《SpringBoot入门宝典》
🎈 本系列主要输出作者自创的开源项目
🔗 作品:前往《 AI 捣蛋屋》, 体验最新AI技术的平台,提供AI论文写作、多功能GPT智能体、智能UI生成以及计算机课程设计源码服务,助力学术研究与开发效率提升。
引言
最近做了一些对接 ChatGPT
的应用,深入了解了一下使用 SSE
来实现接口流式打印的功能。那么接下来就跟着文章了解一下 ChatGPT
的流式功能是如何实现的吧。
目前市面上的 Web
应用中,实时数据传输是一个重要的功能需求。无论是在线聊天、股票行情更新,还是实时通知,实时通信技术都扮演着关键角色。SSE(Server-Sent Events)
作为一种基于HTTP
协议的轻量级实时推送技术,允许服务器向客户端单向传输数据,特别适合用于需要实时更新的场景。
相比WebSocket
这种双向通信协议,SSE
更简单,兼容性更好,且在多数应用场景下能够满足实时数据推送的需求。尤其是在需要从服务器向客户端频繁推送更新,但不需要客户端频繁回应的情况下,SSE
无疑是一个理想的选择。
本文将详细介绍如何在Spring Boot
中集成SSE
,实现类似ChatGPT
的流式交互功能。下面我们将从SSE
的基础知识开始,逐步讲解如何配置项目依赖、实现核心功能,并最终完成一个能够进行实时流式交互的应用。
SSE
基础知识
什么是SSE
?
SSE(Server-Sent Events)
是一种允许服务器主动向客户端发送更新的技术。它建立在HTTP
协议之上,通过简单的文本格式进行数据传输。与传统的请求-响应模式不同,SSE
保持客户端与服务器之间的长连接,使得服务器能够实时向客户端推送数据。
SSE
的几个关键特性包括:
- 单向通信:服务器可以持续向客户端发送数据,但客户端不能主动向服务器发送数据。
- 简单性:
SSE
基于HTTP
协议,易于集成和使用,特别适合Web
应用。 - 自动重连:当连接中断时,
SSE
支持自动重连,确保数据传输的连续性。
SSE
与WebSocket
的对比
在实现实时通信时,WebSocket通常被视为更强大的选择,因为它支持双向通信。然而,在一些应用场景中,SSE却因其简单性和兼容性而更为适用。
SSE
的优势:- 简单性:基于
HTTP
协议,开发者无需引入复杂的协议处理。 - 兼容性好:
SSE
在浏览器端有更广泛的兼容性,尤其适用于那些不支持WebSocket
的环境。 - 轻量级:适合用于服务器到客户端的单向推送,特别是简单的实时通知场景。
- 简单性:基于
WebSocket
的优势:- 双向通信:
WebSocket
支持服务器与客户端之间的双向数据传输,适用于需要频繁互动的场景,如在线聊天或多人协作。 - 低延迟:
WebSocket
在维持长连接的情况下,能够实现低延迟的实时通信。
- 双向通信:
因此,如果你的应用需要实现复杂的双向交互,WebSocket
可能是更合适的选择;而对于一些只需要简单、单向实时数据推送的场景,SSE
则是一个更轻便的方案。
项目结构与依赖配置
Maven
依赖配置
在Spring Boot
项目中使用SSE
,我们需要添加相关的依赖。在pom.xml
文件中,确保引入了Spring Boot
的核心依赖,以及用于HTTP
通信的依赖项。
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.1</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.9</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
在以上配置中,spring-boot-starter-web
提供了Web应用的基础功能,hutool-all
是一个实用的Java工具类库,lombok
则简化了Java
代码的编写。接下来,将重点介绍如何在Controller
层和前端页面中实现SSE
交互。
实现ChatGPT
流式交互的核心代码
Controller
层的实现
我们首先在Controller
中实现SSE
的消息推送逻辑。以下是一个简单的ChatController
示例,它接受来自客户端的消息,并以流式的方式返回响应数据。
@RestController
public class ChatController {
private final Map<String, String> msgMap = new ConcurrentHashMap<>();
@PostMapping("/sendMsg")
public String sendMsg(@RequestParam String msg) {
String msgId = IdUtil.simpleUUID();
msgMap.put(msgId, msg);
return msgId;
}
@GetMapping(value = "/conversation/{msgId}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter conversation(@PathVariable("msgId") String msgId) {
SseEmitter emitter = new SseEmitter();
String msg = msgMap.remove(msgId);
new Thread(() -> {
try {
for (int i = 0; i < 10; i++) {
ChatMessage chatMessage = new ChatMessage("ChatGPT", "Message part " + i);
emitter.send(chatMessage);
Thread.sleep(1000);
}
emitter.send(SseEmitter.event().name("stop").data(""));
emitter.complete();
} catch (IOException | InterruptedException e) {
emitter.completeWithError(e);
}
}).start();
return emitter;
}
}
在这个例子中,sendMsg
方法接收并存储客户端的消息,conversation
方法使用SSE与客户端保持长连接,并按顺序返回多个消息片段,模拟流式输出的效果。
前端页面的实现
前端页面通过HTML
和JavaScript
与服务器进行交互。以下是一个简单的HTML
文件,用于展示与服务器的SSE
交互。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ChatGPT Stream</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
<h1>ChatGPT Stream</h1>
<div id="chatWindow">
<div id="outputTxt"></div>
</div>
<input type="text" id="sendTxt" placeholder="Type a message">
<button id="sendBtn">Send</button>
<script>
$('#sendBtn').on('click', function() {
var msg = $('#sendTxt').val();
$.post('/sendMsg', {msg: msg}, function(data) {
var eventSource = new EventSource('/conversation/' + data);
eventSource.onmessage = function(event) {
$('#outputTxt').append('<p>' + event.data + '</p>');
};
eventSource.onerror = function() {
eventSource.close();
};
});
});
</script>
</body>
</html>
在这个页面中,用户可以输入消息并发送给服务器。服务器会通过SSE
推送返回数据,并在页面上动态显示。
测试与验证
在本地启动我们新建的 SpringBoot
工程项目之后在浏览器端输入链接 http://localhost:8080/chat/index
来访问我刚刚写的那个页面进行接口的测试工作,只需要在页面中的输入框中输入内容并点击发送按钮即可看到页面中数据的实时更新,以此来验证 SSE
的流式交互效果。效果图如下所示:
总结如下
通过集成SSE
,我们在Spring Boot
项目中实现了一个简单而高效的实时数据推送机制。SSE
的轻量级和易用性使其成为处理实时通知和更新的理想选择。在未来的开发中,我们可以进一步优化该实现,或扩展到其他实时数据场景,如股票行情、实时监控等。