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

基于Spring-boot-websocket的聊天应用开发总结

目录

1.概述

1.1 Websocket

1.2 STOMP

1.3 源码

2.Springboot集成WS

2.1 添加依赖

2.2 ws配置

2.2.1 WebSocketMessageBrokerConfigurer

2.2.2 ChatController

2.2.3 ChatInRoomController

2.2.4 ChatToUserController

2.3 前端聊天配置

2.3.1 index.html和main.js

2.3.2 chatInRoom.html和chatInRoom.js

2.3.3 chatToUser.html和chatToUser.js

2.4 测试

2.4.1 基础的发布订阅测试

2.4.2 群聊测试

2.4.3 私聊测试

3 参考总结


最近在研究通过spring-boot-websocket开发简单的聊天应用,以下对这几天做一下总结。

关于WebRTC原理我主要是通过《WebRTC音视频实时互动技术原理、实战与源码分析》这本书了解底层的框架和实现思路,电子版资料可以私聊我。

1.概述

1.1 Websocket

WebSocket 连接允许客户端服务器进行全双向通信,以便任一方都可以通过建立的连接将数据推送到另一端。WebSocket 只需要建立一次连接,就可以一直保持连接状态。这相比于轮询方式的不停建立连接显然效率要大大提高。

如果仅使用WebSocket完成群聊、私聊功能时需要自己管理session信息,但通过STOMP协议时,Spring已经封装好,开发者只需要关注自己的主题、订阅关系即可。

1.2 STOMP

STOMP即“面向消息的简单文本协议”,提供了能够协作的报文格式,以至于 STOMP 客户端可以与任何 STOMP 消息代理(Brokers)进行通信,从而为多语言,多平台和 Brokers 集群提供简单且普遍的消息协作。

STOMP 协议可以建立在WebSocket 之上,也可以建立在其他应用层协议之上。通过 Websocket建立 STOMP 连接,也就是说在 Websocket 连接的基础上再建立 STOMP 连接。最终实现如上图所示,这一点可以在代码中有一个良好的体现。

主要包含如下几个协议事务:

  • CONNECT:启动与服务器的流或 TCP 连接
  • SEND:发送消息
  • SUBSCRIBE:订阅主题
  • UNSUBSCRIBE:取消订阅
  • BEGIN:启动事务
  • COMMIT:提交事务
  • ABORT:回滚事务
  • ACK:确认来自订阅的消息的消费
  • NACK:告诉服务器客户端没有消费该消息
  • DISCONNECT:断开连接

1.3 源码

git地址:https://github.com/BAStriver/spring-boot-websocket-chat-app

下载路径:https://download.csdn.net/download/BAStriver/88711460

2.Springboot集成WS

2.1 添加依赖

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-messaging</artifactId><version>6.0.7</version></dependency>
</dependencies>

2.2 ws配置

2.2.1 WebSocketMessageBrokerConfigurer

这里主要是配置STOMP协议端点、消息代理。

并且设置了前端发布消息的前缀为/app,和消息代理的前缀/topic(@SendTo中为/topic/*)。

// register STOMP endpoints
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {registry.addEndpoint("/ws") // this is the endpoint which should be set in SockJS client.setAllowedOriginPatterns("*") // allow cross-domain request.withSockJS(); // use SockJS protocol
}// register message broker
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {// while sending messages in front end, the path should add the prefix as /appregistry.setApplicationDestinationPrefixes("/app");// enable and set the prefixes of broker paths, like /topic/public// without this prefix, it will block those sent messagesregistry.enableSimpleBroker("/topic", "/user");// while sending messages to user in front end, the path should add the prefix as /user// default is /userregistry.setUserDestinationPrefix("/user");
}

2.2.2 ChatController

以下是基础的控制器,通过sendMessage()发布消息,通过addUser()把订阅者加入到session管理,并最终返回到订阅路径/topic/public。 

@MessageMapping("/chat.sendMessage")
@SendTo("/topic/public")
public ChatMessage sendMessage(@Payload ChatMessage chatMessage
) {return chatMessage;
}@MessageMapping("/chat.addUser")
@SendTo("/topic/public")
public ChatMessage addUser(@Payload ChatMessage chatMessage,SimpMessageHeaderAccessor headerAccessor
) {// Add username in web socket sessionheaderAccessor.getSessionAttributes().put("username", chatMessage.getSender());return chatMessage;
}

经过上面的方法可以实现发布订阅模式。

值得注意的是,如果没有配置@SendTo,则消息会默认返回到@MessageMapping的路径给订阅者。

2.2.3 ChatInRoomController

这个主要是实现群聊。

@MessageMapping("/chat/{roomId}")
@SendTo("/topic/chat/{roomId}") // if not add @SendTo, then by default will send to the path /topic/chat/{roomId}
public ChatMessage sendMessage(@DestinationVariable String roomId, ChatMessage message) {log.info("roomId: {}", roomId);return message;
}// if need the {roomId} in @SendTo,
// then should add {roomId} in @MessageMapping and sent roomId from front end.
// otherwise, it could not resolve placeholder 'roomId' in value "/topic/chat/{roomId} of @SendTo
@MessageMapping("/chat.addUserToRoom/{roomId}")
@SendTo("/topic/chat/{roomId}")
public ChatMessage addUser(@Payload ChatMessage chatMessage,SimpMessageHeaderAccessor headerAccessor
) {// Add username in web socket sessionheaderAccessor.getSessionAttributes().put("username", chatMessage.getSender());return chatMessage;
}

值得注意的是,如果@SendTo需要{roomId}这个参数,那么在@MessageMapping()中也需要传入{roomId}。

2.2.4 ChatToUserController

这个主要实现单独发布消息到指定的订阅者。

@MessageMapping("/chatToUser/{userId}")
@SendTo(value = "/topic/chatToUser/{userId}")
public ChatMessage sendMessage(@DestinationVariable String userId, ChatMessage message,SimpMessageHeaderAccessor headerAccessor) {log.info("send to the userId: {}", userId);log.info("message: {}", message);//        Set<StompAuthenticatedUser> collect = simpUserRegistry.getUsers().stream()
//                .map(simpUser -> StompAuthenticatedUser.class.cast(simpUser.getPrincipal()))
//                .collect(Collectors.toSet());
//        collect.forEach(user -> {
//            if(user.getNickName().equals(userId)) {
//                simpMessagingTemplate.convertAndSendToUser(userId, "/chatToUser/"+userId, message);
//            }
//        });return message;
}@MessageMapping("/chat.helloUser/{userId}")
@SendTo("/user/chat/{userId}")
public ChatMessage helloUser(@DestinationVariable String userId,@Payload ChatMessage chatMessage,SimpMessageHeaderAccessor headerAccessor
) {// Add username in web socket sessionheaderAccessor.getSessionAttributes().put("username", chatMessage.getSender());headerAccessor.getSessionAttributes().put("userid", userId);// use the tool to send the message to public topic directly, without @MessageMapping// simpMessagingTemplate.convertAndSend("/user/chat/" + userId, chatMessage);return chatMessage;
}//@MessageMapping("/chat.sendMessage")
@GetMapping("/testSendMessage")
public void testSendMessage(ChatMessage message) {// use the tool to send the message to public topic directly, without @MessageMappingsimpMessagingTemplate.convertAndSend("/topic/public", message);
}

值得注意的是,这里的@MesssageMapping()不要和前面的重复了。

同样的,也可以通过如下的代码实现发布消息。

simpMessagingTemplate.convertAndSend("/user/chat/" + userId, chatMessage);

其实这个部分和#2.2.3同理,不同的是私聊其实可以用@SendToUser。 

2.3 前端聊天配置

SockJS 是一个浏览器的 JavaScript库,它提供了一个类似于网络的对象,SockJS 提供了一个连贯的,跨浏览器的JavaScriptAPI,它在浏览器和 Web 服务器之间创建了一个低延迟、全双工、跨域通信通道。SockJS 的一大好处在于提供了浏览器兼容性。即优先使用原生WebSocket,如果浏览器不支持 WebSocket,会自动降为轮询的方式。如果你使用 Java 做服务端,同时又恰好使用 Spring Framework 作为框架,那么推荐使用SockJS。

2.3.1 index.html和main.js

对应#2.2.2的前端页面和脚本。

这里初始化一个sockjs实例,其中的/ws指定了#2.2.1的STOMP端点。

function connect(event) {username = document.querySelector('#name').value.trim();if(username) {usernamePage.classList.add('hidden');chatPage.classList.remove('hidden');const header = {"User-ID": new Date().getTime().toString(),"User-Name": username};var socket = new SockJS('/ws'); // set the STOMP endpointstompClient = Stomp.over(socket);stompClient.connect(header, onConnected, onError);}event.preventDefault();
}

当客户端和服务Connected之后,开始订阅/topic/public的消息以及设置send()的消息发布路径。

function onConnected() {// Subscribe to the Public TopicstompClient.subscribe('/topic/public', onMessageReceived);// Tell your username to the serverstompClient.send("/app/chat.addUser", // prefix with /app{},JSON.stringify({sender: username, type: 'JOIN'}))connectingElement.classList.add('hidden');
}function sendMessage(event) {var messageContent = messageInput.value.trim();if(messageContent && stompClient) {var chatMessage = {sender: username,content: messageInput.value,type: 'CHAT'};stompClient.send("/app/chat.sendMessage", {}, JSON.stringify(chatMessage));messageInput.value = '';}event.preventDefault();
}

值得注意的是,这里send()的时候要记得加/app作为前缀。

2.3.2 chatInRoom.html和chatInRoom.js

对应#2.2.3的前端页面和脚本。

初始化sockjs实例和上面的一样,但要注意的是Connected之后的订阅和发布路径加上了{room}作为聊天室的id。

function onConnected() {// Subscribe the message of the {room}stompClient.subscribe('/topic/chat/'+room, onMessageReceived);// Tell your username to the serverstompClient.send("/app/chat.addUserToRoom/"+room, // prefix with /app{},JSON.stringify({sender: username, type: 'JOIN'}))connectingElement.classList.add('hidden');
}function sendMessage(event) {var messageContent = messageInput.value.trim();if(messageContent && stompClient) {var chatMessage = {sender: username,content: messageInput.value,type: 'CHAT'};stompClient.send("/app/chat/"+room, {}, JSON.stringify(chatMessage));messageInput.value = '';}event.preventDefault();
}

2.3.3 chatToUser.html和chatToUser.js

对应#2.2.3的前端页面和脚本。

初始化sockjs实例和上面的一样,但要注意的是Connected之后的订阅和发布路径加上了{username}和{userid}作为私聊对象id。

function onConnected() {console.log('username: ', username);console.log('userid: ', userid);// Subscribe the message with {userid}stompClient.subscribe('/user/chat/' + username, onMessageReceived);stompClient.subscribe('/topic/chatToUser/' + username, onMessageReceived);// Tell your username to the serverstompClient.send("/app/chat.helloUser/" + username, // prefix with /app{},JSON.stringify({sender: username, type: 'JOIN'}))connectingElement.classList.add('hidden');
}function sendMessage(event) {var messageContent = messageInput.value.trim();if (messageContent && stompClient) {var chatMessage = {sender: username,content: messageInput.value,type: 'CHAT'};stompClient.send("/app/chatToUser/" + userid, {}, JSON.stringify(chatMessage));messageInput.value = '';}event.preventDefault();
}

2.4 测试

2.4.1 基础的发布订阅测试

这里测试的#2.3.1的部分。

首先是登录界面,进入:http://localhost:8080/index.html

打开两个index页面,然后输入username之后实现聊天。

第一个index.html登入BAS用户,第二个页面登入BAS55。

2.4.2 群聊测试

这里测试的#2.3.2的部分。

首先是登录界面,进入:http://localhost:8080/chatInRoom.html

第一个index.html登入BAS用户(Room: 12345),

第二个页面登入BAS55(Room: 12345),

第三个页面登入BAS10(Room: 123),BAS10单独在一个房间

2.4.3 私聊测试

这里测试的#2.3.3的部分。

首先是登录界面,进入:http://localhost:8080/chatToUser.html

第一个index.html登入BAS用户(Chat To: BAS5),

第二个页面登入BAS55(Chat To: BAS),

第三个页面登入BAS10(Chat To: BAS9)。

3 参考总结

以下是开发过程中参考并且觉得挺有帮助的资料:

SpringBoot——整合WebSocket(STOMP协议) - 简书

Spring Boot系列 WebSocket集成简单消息代理_websocketmessagebrokerconfigurer-CSDN博客

WebSocket的那些事(4-Spring中的STOMP支持详解)_simpuserregistry 为空-CSDN博客

注:

1.关于@MessageMapping()的使用可以参考:Spring Boot中的@MessageMapping注解:原理及使用-CSDN博客

2.关于AbstractWebSocketHandler的使用可以参考:WebSocket基本概念及在Spring Boot中的使用 - 知乎

3.关于@SendTo()和@SendToUser()的区别和使用可以参考:在Spring WebSocket中使用@SendTo和@SendToUser进行消息路由 - 实时互动网

Spring-messaging (STOMP) @SendTo 与 @SendToUser的区别-CSDN博客

相关文章:

基于Spring-boot-websocket的聊天应用开发总结

目录 1.概述 1.1 Websocket 1.2 STOMP 1.3 源码 2.Springboot集成WS 2.1 添加依赖 2.2 ws配置 2.2.1 WebSocketMessageBrokerConfigurer 2.2.2 ChatController 2.2.3 ChatInRoomController 2.2.4 ChatToUserController 2.3 前端聊天配置 2.3.1 index.html和main.j…...

2023年度总结 - 职业生涯第一个十年

2023年只剩下最后一周&#xff0c;又到了一年一度该做年末总结的时候了。 回想起去年&#xff0c;还有人专门建立了一个关于年度总结文章汇总的仓库。读了很多篇别人写的&#xff0c;给了我很多的触动和感想。这里的每篇文章都是关于某个人这一整年的生活和工作的轨迹啊。即使你…...

setup 语法糖

只有vue3.2以上版本可以使用 优点&#xff1a; 更少的样板内容&#xff0c;更简洁的代码 能够使用纯 Typescript 声明props 和抛出事件 更好的运行时性能 更好的IDE类型推断性能 在sciprt标识上加上setup 顶层绑定都可以使用 不需要return &#xff0c;可以直接使用 使用组件…...

Javaweb之Mybatis的基础操作的详细解析

1. Mybatis基础操作 学习完mybatis入门后&#xff0c;我们继续学习mybatis基础操作。 1.1 需求 需求说明 通过分析以上的页面原型和需求&#xff0c;我们确定了功能列表&#xff1a; 查询 根据主键ID查询 条件查询 新增 更新 删除 根据主键ID删除 根据主键ID批量删除 …...

知名开发者社区Stack Overflow发布《2023 年开发者调查报告》

Stack Overflow成立于2008年&#xff0c;最知名的是它的公共问答平台&#xff0c;每月有超过 1 亿人访问该平台来提问、学习和分享技术知识。是世界上最受欢迎的开发者社区之一。每年都会发布一份关于开发者的调查报告&#xff0c;来了解不断变化的开发人员现状、正在兴起或衰落…...

vue element plus Form 表单

表单包含 输入框, 单选框, 下拉选择, 多选框 等用户输入的组件。 使用表单&#xff0c;您可以收集、验证和提交数据。 TIP Form 组件已经从 2. x 的 Float 布局升级为 Flex 布局。 典型表单# 最基础的表单包括各种输入表单项&#xff0c;比如input、select、radio、checkbo…...

zmq_connect和zmq_poll

文章内容&#xff1a; 介绍函数zmq_connect和zmq_poll的使用 zmq_connect zmq_connect函数是ZeroMQ库中的一个函数&#xff0c;用于在C语言中创建一个与指定地址的ZeroMQ套接字的连接。该函数的原型如下&#xff1a; int zmq_connect(void *socket, const char *endpoint);其…...

TinyLog iOS v3.0接入文档

1.背景 为在线教育部提供高效、安全、易用的日志组件。 2.功能介绍 2.1 日志格式化 目前输出的日志格式如下&#xff1a; 日志级别/[YYYY-MM-DD HH:MM:SS MS] TinyLog-Tag: |线程| 代码文件名:行数|函数名|日志输出内容触发flush到文件的时机&#xff1a; 每15分钟定时触发…...

react-native 配置@符号绝对路径配置和绝对路径没有提示的问题

这里需要用到vscode的包 yarn add babel-plugin-module-resolver 找到根目录里的babel.config.js 在页面添加plugins配置 直接替换 module.exports {presets: [module:metro-react-native-babel-preset],plugins: [[module-resolver,{root: [./src],alias: {/utils: ./src/…...

element的Table表格组件树形数据与懒加载简单使用

目录 1. 代码实现2. 效果图3. 解决新增、删除、修改之后树节点不刷新问题。&#xff08;[参考文章](https://blog.csdn.net/weixin_41549971/article/details/135504471)&#xff09; 1. 代码实现 <template><div><!-- lazy 是否懒加载子节点数据 --><!-…...

游戏、设计选什么内存条?光威龙武系列DDR5量大管饱

如果你是一位PC玩家或者创作者&#xff0c;日常工作娱乐中&#xff0c;确实少不了大容量高频内存的支持&#xff0c;这样可以获得更高的工作效率&#xff0c;光威龙武系列DDR5内存条无疑是理想之选。它可以为计算机提供强劲的性能表现和稳定的运行体验&#xff0c;让我们畅玩游…...

linux磁盘清理_docker/overlay2爆满

问题&#xff1a;无意间发现linux服务器登陆有问题&#xff0c;使用df命令发现目录满了。 1. 确定哪里占用了大量内存。 cd / du -sh * | sort -rh经过一段时间后&#xff0c;显示如下&#xff1a; // 474G home // 230G var // 40G usr // 10G snap // --- 根据实际情…...

Redis过期清理策略和内存淘汰机制

目录 Redis过期清理策略Redis内存淘汰机制 Redis过期清理策略 Redis 通过设置键的过期时间来实现自动删除过期键。当键的过期时间到达时&#xff0c;Redis 会自动将该键删除。Redis 过期清理策略主要有以下两种&#xff1a; 惰性删除&#xff1a;Redis 在获取键时会检查键是否…...

2_并发编程同步锁(synchronized)

并发编程带来的安全性同步锁(synchronized) 1.他的背景 当多个线程同时访问&#xff0c;公共共享资源的时候&#xff0c;这时候就会出现线程安全&#xff0c;代码如&#xff1a; public class AtomicDemo {int i0;//排他锁、互斥锁public void incr(){ //synchronizedi; …...

Python 常用模块pickle

Python 常用模块pickle pickle序列化模块 【一】定义 序列化&#xff1a;将数据结构或对象转换为可存储或传输的格式反序列化&#xff1a;将序列化后的数据恢复为开始的数据结构或者对象 【二】目的 数据持久化存储远程通信缓存进程间通信 【三】序列化 将对象转换为字节…...

CentOS 6 制作openssh 9.6 p1 rpm包(含ssh-copy-id、openssl) —— 筑梦之路

openssh 9.6 需要openssl 1.1.1 以上版本&#xff0c;因此需要先安装openssl 1.1.1&#xff0c;可阅读这篇升级更新openssl版本到1.1.1w CentOS 6 制作openssl 1.1.1w rpm包 —— 筑梦之路-CSDN博客 CentOS 6很久都停止更新和支持&#xff0c;关于此版本的写的不多&#xff…...

Tomcat Notes: Deployment File

This is a personal study notes of Apache Tomcat. Below are main reference material. - YouTube Apache Tomcat Full Tutorial&#xff0c;owed by Alpha Brains Courses. https://www.youtube.com/watch?vrElJIPRw5iM&t801s 1、Tomcat deployment1.1、Two modes of …...

某邦通信股份有限公司IP网络对讲广播系统挖矿检测脚本

目录 1.漏洞概述 2.影响版本 3.危害等级 4.挖矿程序检测 5.Nuclei自动化检测...

uniapp点击跳转传对象

目录 传对象传对象传送组件接受组件 最后 传对象 传对象 传送组件 点击传给组件 <view class"dki-tit-edit" click"gotificatedit(item)">编辑 </view>gotificatedit(item){console.log(item,item);let options JSON.stringify(item);uni.…...

简单用PHP实现微信小程序的游戏功能

微信小程序的兴起&#xff0c;越来越多的开发者开始关注如何在小程序中实现游戏功能。PHP作为一种流行的后端语言&#xff0c;可以很好地与小程序进行搭配&#xff0c;实现游戏功能。下面将介绍如何使用PHP来实现微信小程序的游戏功能&#xff0c;并提供具体的代码示例。 建立…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

设计模式和设计原则回顾

设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能&#xff0c;包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

Kafka主题运维全指南:从基础配置到故障处理

#作者&#xff1a;张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1&#xff1a;主题删除失败。常见错误2&#xff1a;__consumer_offsets占用太多的磁盘。 主题日常管理 …...

深入浅出Diffusion模型:从原理到实践的全方位教程

I. 引言&#xff1a;生成式AI的黎明 – Diffusion模型是什么&#xff1f; 近年来&#xff0c;生成式人工智能&#xff08;Generative AI&#xff09;领域取得了爆炸性的进展&#xff0c;模型能够根据简单的文本提示创作出逼真的图像、连贯的文本&#xff0c;乃至更多令人惊叹的…...