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

Spring WebSocket 与 STOMP 协议结合实现私聊私信功能

目录

    • 后端
      • pom.xml
      • Config配置类
      • Controller类
      • DTO
    • 前端
      • 安装相关依赖
      • websocketService.js接口
      • javascript
      • html
      • CSS
    • 效果展示
      • 简单测试连接:
    • 报错解决方法
      • 1、vue3 使用SockJS报错 ReferenceError: global is not defined
    • 功能补充拓展
      • 1. 安全性和身份验证
      • 2. 异常处理
      • 3. 消息广播的功能
      • 4. 配置 WebSocket 消息缓存和负载均衡
      • 5. 客户端连接管理
      • 6. WebSocket 消息格式和编码
      • 总结
    • 后面将继续完善,待更新...

后端

pom.xml

		<!-- Spring Boot WebSocket--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><!-- Spring Boot 数据库支持 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!-- MySQL 驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!-- Thymeleaf(如果你使用了模板) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!-- Spring Boot Web 支持 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency>

Config配置类

注意:允许源根据自己项目修改

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;@Configuration
@EnableWebSocketMessageBroker
@Slf4j
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {@Overridepublic void configureMessageBroker(MessageBrokerRegistry config) {config.enableSimpleBroker("/queue", "/topic","/user");config.setApplicationDestinationPrefixes("/app");}@Overridepublic void registerStompEndpoints(StompEndpointRegistry registry) {registry.addEndpoint("/ws")
//        在 WebSocket 握手时,我们可以通过 URL 参数或者 HTTP headers 传递用户身份信息。
//                .addInterceptors(new MyHandshakeInterceptor())// 添加拦截器.setAllowedOrigins("http://127.0.0.1:8889", "http://localhost:8889", "http://localhost:8888", "http://127.0.0.1:8888", "http://localhost:8000","http://localhost:8890","http://127.0.0.1:8890").withSockJS();  // 添加 SockJS 支持}
}

Controller类

import com.tianwen.mapper.UserMessagesMapper;
import com.tianwen.user.dtos.MessageDTO;
import com.tianwen.user.pojos.Messages;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import java.time.LocalDateTime;@Controller
public class ChatController {@Autowiredprivate UserMessagesMapper userMessagesMapper;@Autowiredprivate SimpMessagingTemplate messagingTemplate; // 注入消息模板,用于发送消息到指定目的地@MessageMapping("/chat.sendMessage")//这个注解用来监听来自前端的 WebSocket 消息,路径是 /app/chat.sendMessage,当前端发送消息到这个路径时,sendMessage 方法会被触发。
//    @SendTo("/topic/messages")//这个注解表明处理完消息后,返回的消息将广播给订阅了 /topic/messages 路径的所有客户端。public MessageDTO sendMessage(MessageDTO messageDTO) throws Exception {System.out.println("接收到的message:"+messageDTO);// 1. 可以在这里进行私信存储到数据库操作Messages messages = new Messages();messages.setSenderId(messageDTO.getSenderId());messages.setReceiverId(messageDTO.getReceiverId());messages.setContent(messageDTO.getContent());messages.setCreateTime(LocalDateTime.now());// 2. 保存私信消息(插入操作)if (userMessagesMapper.insert(messages) <= 0) {// 如果插入失败,可以返回错误或做其他处理return null;}// 3. 实时将消息转发给接收者String receiverIdStr = String.valueOf(messageDTO.getReceiverId());  // 将 receiverId 转换为 StringString receiverDestination = "/user/" + receiverIdStr + "/queue/messages";//通过 SimpMessagingTemplate 的 convertAndSendToUser 方法,将消息实时推送给接收者。//推送的目标是 /user/{receiverId}/queue/messages,该路径是给特定用户的私有消息队列。messagingTemplate.convertAndSendToUser(receiverIdStr, receiverDestination, messageDTO);return messageDTO;}
}

DTO

import lombok.Data;
@Data
public class MessageDTO {private Integer senderId;private Integer receiverId;private String content;
}

前端

安装相关依赖

npm install sockjs-client@latest
npm install @stomp/stompjs sockjs-client
npm install global    
npm i --save-dev @types/sockjs-client 

websocketService.js接口

注意:服务器地址根据自己的修改(application.yml)

// websocketService.js
// Stomp.js:用于处理 STOMP 协议,它在 WebSocket 基础上实现了消息订阅、发送等功能。
import { Stomp } from "@stomp/stompjs";
//SockJS:是一个用于实现 WebSocket 的库,它为 WebSocket 提供了回退机制(例如 HTTP 长轮询等),确保在不同浏览器和网络环境下的兼容性。
import SockJS from "sockjs-client/dist/sockjs.min.js";
export default {connect(onMessageReceived) {//使用 SockJS 和 Stomp 创建一个 WebSocket 客户端,连接到后端的 WebSocket 服务 http://localhost:8000/ws。const socket = new SockJS("http://localhost:8000/ws"); // 使用 SockJS 连接const stompClient = Stomp.over(socket);const userId = JSON.parse(localStorage.getItem("userId"));stompClient.connect({}, () => {console.log("本人消息队列ID:", userId);//在连接成功后,通过 stompClient.subscribe 订阅 /topic/messages,接收从后端广播过来的消息。// stompClient.subscribe("/topic/messages", (messageOutput) => {//   onMessageReceived(JSON.parse(messageOutput.body));// });// 订阅当前用户的私有消息队列stompClient.subscribe("/user/" + userId + "/queue/messages",(messageOutput) => {onMessageReceived(JSON.parse(messageOutput.body)); // 处理接收到的私聊消息});// 订阅当前用户的私有消息队列;// stompClient.subscribe(//   "/user/" + userId + "/queue/messages",//   function (messageOutput) {//     const message = JSON.parse(messageOutput.body);//     console.log("接收到私信:", message);//   }// );});// 连接到 WebSocket 后,订阅用户消息// stompClient.connect({}, function (frame) {//   // 获取当前用户ID//   const userId = getCurrentUserId(); // 假设这个方法能够获取当前用户的ID//   // 订阅接收者的消息队列// stompClient.subscribe(//   "/user/" + userId + "/queue/messages",//   function (messageOutput) {//     const message = JSON.parse(messageOutput.body);//     console.log("接收到私信:", message);//   }// );// });},sendMessage(message) {console.log("发送消息接口1:", message);const socket = new SockJS("http://localhost:8000/ws"); // 使用 SockJS 连接const stompClient = Stomp.over(socket);stompClient.connect({}, () => {//当用户输入消息时,通过 stompClient.send 方法将消息发送到 /app/chat.sendMessage,这个路径会将消息推送到后端进行处理。stompClient.send("/app/chat.sendMessage", {}, JSON.stringify(message));});},
};

javascript

<script setup lang="ts">
import '@wangeditor/editor/dist/css/style.css' // 引入 css
import { onBeforeUnmount, ref, shallowRef, onMounted } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import type { IToolbarConfig, IEditorConfig } from "@wangeditor/editor";
const editorRef = shallowRef();
import websocketService from "@/api/websocketService.js";
import {ref,onMounted,
} from "vue";
import websocketService from "@/api/websocketService.js";const receiverIdAnswer = ref();
const sendPrivateMessage = () => {dialogVisible.value = true;
};
const sendPrivateMessage = async (userId) => {receiverIdAnswer.value = userId;dialogVisible.value = true;const response = await getAuthorDetailsByUserId(userId);console.log("response", userId);privateMessagesUser.value = response.data;console.log("privateMessagesUser", privateMessagesUser.value);
};const dialogVisible = ref(false);interface Message {id: string;senderId: string;receiverId: string;content: string;
}const messages = ref<Message[]>([]); // 明确指定消息数组的类型const newMessage = ref("");onMounted(() => {websocketService.connect((message: Message) => {// 明确指定回调函数的参数类型messages.value.push(message);});
});const sendMessage = () => {if (newMessage.value.trim()) {const message: Message = {// 明确声明消息类型id: Date.now().toString(), // 使用当前时间戳作为唯一 IDsenderId: userInfo.value.id, // Example senderreceiverId: receiverIdAnswer.value, // Example receivercontent: newMessage.value,};websocketService.sendMessage(message);newMessage.value = "";}
};
const editorConfig: Partial<IEditorConfig> = {placeholder: "请输入...",MENU_CONF: {},
};
const handleCreated = (editor) => {editorRef.value = editor;
};
// 排除富文本的菜单项
const toolbarConfigPrivateMessages: Partial<IToolbarConfig> = {// toolbar 配置excludeKeys: ["headerSelect","blockquote","|","bold","underline","italic","group-more-style", // 排除菜单组,写菜单组 key 的值即可"color","bgColor","|","fontSize","fontFamily","lineHeight","bulletedList","numberedList","todo","group-justify","group-indent","insertLink","group-video","insertTable","codeBlock","divider","undo","redo","fullScreen",],
};
</script>

html

 <!-- 私信聊天框 --><el-dialog v-model="dialogVisible"><template #title><div style="text-align: center; font-weight: bold">{{ privateMessagesUser.username }}</div><hr class="line" /></template><div class="chat-container"><div class="messages" ref="messagesContainer"><divv-for="message in messages":key="message.id":class="{'my-message': message.senderId === userInfo.id,'other-message': message.senderId !== userInfo.id,}"><div style="display: flex; flex-direction: row"><div><el-image:src="userInfo.avatarUrl"style="width: 45px; border-radius: 50%"></el-image></div><div style="margin-top: 5px; margin-left: 10px"><div><strong>{{ userInfo.username }}</strong></div><divclass="message-bubble message-green"v-html="message.content"></div></div></div></div></div></div><div style="border: 1px solid #ccc"><Toolbarstyle="border-bottom: 1px solid #ccc":editor="editorRef":defaultConfig="toolbarConfigPrivateMessages"mode="default"/><Editorstyle="height: 200px; overflow-y: hidden"v-model="newMessage"@keyup.enter="sendMessage":defaultConfig="editorConfig"mode="default"@onCreated="handleCreated"/></div><template #footer><el-button @click="dialogVisible = false">取消</el-button><el-button type="primary" @click="sendMessage">发送</el-button></template></el-dialog>

CSS

<style scoped>
/* 私信样式 */
/* 标题居中 */
/* .private-message-dialog {
} */
.line {border-top: 1px solid #ccc; /* 直线的样式,可以修改颜色 */
}/* 聊天框滚动 */
.chat-container {display: flex;flex-direction: column;height: 300px;overflow-y: auto;box-sizing: border-box; /* 让 padding 和 border 包含在宽度和高度内 */
}.chat-container > * {width: 100%; /* 确保所有子元素不会超出容器宽度 */box-sizing: border-box; /* 确保子元素的宽度计算不受 padding 和 border 影响 */
}/* 消息容器 */
.messages {display: flex;flex-direction: column;gap: 10px;padding: 10px;max-height: 250px;overflow-y: auto;
}/* 发送方和接收方的消息样式 */
.my-message {/* text-align: right; */border-radius: 10px;height: auto;/* padding: 5px 10px; */
}.other-message {/* text-align: left; */border-radius: 10px;/* padding: 5px 10px; */
}.message-bubble {/* max-width: 70%; */padding: 0px 10px;border-radius: 10px;/* height: 30px; *//* margin: 0px 0px 0px 0px; *//* word-wrap: break-word; *//* line-height: 1.4; */font-size: 14px;display: flex;align-items: center;justify-content: center;
}.message-green {background-color: #57c457; /* 微信消息绿色 */color: white;align-self: flex-end; /* 让气泡靠右显示 */
}
</style>

效果展示

在这里插入图片描述

简单测试连接:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

报错解决方法

1、vue3 使用SockJS报错 ReferenceError: global is not defined

解:

import SockJS from “sockjs-client”;

修改为:

import SockJS from “sockjs-client/dist/sockjs.min.js”;

并安装依赖

npm i --save-dev @types/sockjs-client

功能补充拓展

以下是一些可能的补充和优化,确保 WebSocket 能够顺利运行并且高效处理消息。

1. 安全性和身份验证

如果你的 WebSocket 服务需要进行身份验证(如用户登录),你可以考虑在 WebSocket 握手时验证用户身份。你可以在 WebSocketConfig 中添加一个 HandshakeInterceptor 来拦截握手请求,获取 HTTP header 或 URL 参数中的用户信息,确保只有经过身份验证的用户能够连接。

例如:

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {registry.addEndpoint("/ws").addInterceptors(new MyHandshakeInterceptor()) // 添加拦截器.setAllowedOrigins("http://localhost:8889").withSockJS();
}

其中 MyHandshakeInterceptor 可以用来在 WebSocket 握手期间传递用户信息。

2. 异常处理

在 WebSocket 消息处理过程中,你可能会遇到一些异常,如数据库操作失败或消息传输失败等。在控制器中,你可以捕获这些异常并返回相应的错误消息,确保系统更加健壮。

例如:

@MessageMapping("/chat.sendMessage")
public MessageDTO sendMessage(MessageDTO messageDTO) {try {// 消息处理逻辑} catch (Exception e) {log.error("发送消息失败", e);return new MessageDTO("error", "消息发送失败");}
}

3. 消息广播的功能

目前,你的代码实现了将消息发送到指定用户的功能(私信)。如果你希望实现群聊功能或全局广播,可以进一步扩展 @SendTo 注解。这个注解的使用使得你可以将处理后的消息发送给所有订阅某个特定主题的客户端。

例如,广播消息给所有订阅 /topic/messages 的客户端:

@MessageMapping("/chat.sendMessage")
@SendTo("/topic/messages")
public MessageDTO sendMessage(MessageDTO messageDTO) {// 处理消息逻辑return messageDTO;  // 返回的消息会广播给所有订阅 /topic/messages 的客户端
}

4. 配置 WebSocket 消息缓存和负载均衡

如果你的系统需要处理大量的 WebSocket 连接,可能会面临性能和可扩展性的问题。在这种情况下,考虑使用 Redis 等消息队列作为消息代理,可以通过 @EnableWebSocketMessageBroker 配置远程消息代理。

例如,通过 Redis 实现消息广播:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {@Overridepublic void configureMessageBroker(MessageBrokerRegistry config) {config.enableSimpleBroker("/queue", "/topic", "/user");config.setApplicationDestinationPrefixes("/app");// 使用 Redis 消息代理config.setBrokerRegistry().setApplicationDestinationPrefixes("/app").enableStompBrokerRelay("/topic", "/queue").setRelayHost("localhost").setRelayPort(61613);  // 配置Redis(如ActiveMQ)等消息中间件}
}

5. 客户端连接管理

如果你希望在某个用户断开连接时进行一些清理工作(例如清理会话、推送通知等),你可以使用 @OnDisconnect 注解来捕获断开连接事件。

@MessageMapping("/chat.disconnect")
public void handleDisconnect(SessionDisconnectEvent event) {// 用户断开连接时执行的逻辑log.info("用户断开连接,sessionId: " + event.getSessionId());
}

6. WebSocket 消息格式和编码

确保你的客户端和服务端使用相同的消息格式。你可能需要为 WebSocket 消息提供适当的序列化和反序列化器,以确保消息能够正确地从客户端传输到服务端,以及从服务端传输回客户端。

例如,使用 Jackson 或其他库将 Java 对象序列化为 JSON 格式:

@MessageMapping("/chat.sendMessage")
@SendTo("/topic/messages")
public MessageDTO sendMessage(MessageDTO messageDTO) throws Exception {// 消息传输过程中确保使用适当的 JSON 格式return messageDTO;
}

总结

大体上,已经完成了 WebSocket 的配置和处理消息的核心部分,剩下的步骤主要是根据具体业务需求做扩展,如身份验证、消息缓存、广播支持等。如果你的应用规模较大,可能还需要考虑负载均衡和消息队列等高可用性的设计。

后面将继续完善,待更新…

相关文章:

Spring WebSocket 与 STOMP 协议结合实现私聊私信功能

目录 后端pom.xmlConfig配置类Controller类DTO 前端安装相关依赖websocketService.js接口javascripthtmlCSS 效果展示简单测试连接&#xff1a; 报错解决方法1、vue3 使用SockJS报错 ReferenceError: global is not defined 功能补充拓展1. 安全性和身份验证2. 异常处理3. 消息…...

【Matlab高端绘图SCI绘图模板】第05期 绘制高阶折线图

1.折线图简介 折线图是一个由点和线组成的统计图表&#xff0c;常用来表示数值随连续时间间隔或有序类别的变化。在折线图中&#xff0c;x 轴通常用作连续时间间隔或有序类别&#xff08;比如阶段1&#xff0c;阶段2&#xff0c;阶段3&#xff09;。y 轴用于量化的数据&#x…...

java后端之事务管理

Transactional注解&#xff1a;作用于业务层的方法、类、接口上&#xff0c;将当前方法交给spring进行事务管理&#xff0c;执行前开启事务&#xff0c;成功执行则提交事务&#xff0c;执行异常回滚事务 spring事务管理日志&#xff1a; 默认情况下&#xff0c;只有出现Runti…...

常见的多媒体框架(FFmpeg GStreamer DirectShow AVFoundation OpenMax)

1.FFmpeg FFmpeg是一个非常强大的开源多媒体处理框架&#xff0c;它提供了一系列用于处理音频、视频和多媒体流的工具和库。它也是最流行且应用最广泛的框架&#xff01; 官方网址&#xff1a;https://ffmpeg.org/ FFmpeg 的主要特点和功能&#xff1a; 编解码器支持: FFmpe…...

如何移植ftp服务器到arm板子?

很多厂家提供的sdk&#xff0c;一般都不自带ftp服务器功能&#xff0c; 需要要发人员自己移植ftp服务器程序。 本文手把手教大家如何移植ftp server到arm板子。 环境 sdk&#xff1a;复旦微 Buildroot 2018.02.31. 解压 $ mkdir ~/vsftpd $ cp vsftpd-3.0.2.tar.gz ~/vs…...

牛批,吾爱出品

可能是因为从事IT的原因&#xff0c;我身边的大多数朋友也是从事相关工作的&#xff0c;而IT工作往往需要长时间对着电脑。这样就很容易眼睛疲劳。今天给大家推荐几款&#xff0c;希望有对有需要的小伙伴有所帮助&#xff0c;大家可以收藏以来哦。 CareUEyes CareUEyes是一款绿…...

基于 Android 的日程管理系统的设计与实现

标题:基于 Android 的日程管理系统的设计与实现 内容:1.摘要 基于 Android 的日程管理系统旨在帮助用户更高效地管理个人日程安排。该系统采用了 Android 平台的优势&#xff0c;结合了简洁的界面设计和强大的功能&#xff0c;为用户提供了便捷的日程管理体验。 在设计与实现过…...

Kubectl 与 Helm 详解

在 Kubernetes 生态中,kubectl 和 Helm 是两个核心工具,分别用于直接管理 Kubernetes 资源和简化应用的部署与管理。本文将深入探讨 kubectl 和 Helm 的功能、使用场景、部署与更新方式,并对比它们的优缺点。 1. Kubectl 详解 1.1 什么是 Kubectl? kubectl 是 Kubernetes…...

centos搭建docker registry镜像仓库

centos搭建docker registry镜像仓库 简介 Docker Registry是一个存储和分发Docker镜像的服务。它允许用户上传、下载和管理 Docker 镜像&#xff0c;为容器化应用的部署提供了便利。 拉取镜像 docker image pull registry证书配置 创建镜像仓库的镜像数据目录和证书目录&…...

Pyecharts之饼图与多饼图的应用

在数据可视化领域&#xff0c;饼图是一种常用的图表类型&#xff0c;特别适合展示数据的比例关系。Pyecharts 为我们提供了强大的饼图绘制功能&#xff0c;不仅可以轻松绘制各种饼图&#xff0c;还能对饼图的样式和数据标签进行深度定制&#xff0c;并且可以组合多个饼图以满足…...

51单片机入门_01_单片机(MCU)概述(使用STC89C52芯片;使用到的硬件及课程安排)

文章目录 1. 什么是单片机1.1 微型计算机的组成1.2 微型计算机的应用形态1.3 单板微型计算机1.4 单片机(MCU)1.4.1 单片机内部结构1.4.2 单片机应用系统的组成 1.5 80C51单片机系列1.5.1 STC公司的51单片机1.5.1 STC公司单片机的命名规则 2. 单片机的特点及应用领域2.1 单片机的…...

蓝桥杯LQ1044 求完数

题目描述 因子&#xff1a;因子也叫因数&#xff0c;例如3515&#xff0c;那么3和5是15的因子。 同时15115&#xff0c;那么1和15也是15的因子。 1&#xff0c;3&#xff0c;5&#xff0c;15 这四个因子是15的所有因子。 完数&#xff1a;如果一个数等于不含它本身的其他因子之…...

Django 日志配置实战指南

日志是 Django 项目中不可或缺的一部分,它帮助我们记录应用程序的运行状态、调试信息、错误信息等。通过合理配置日志,我们可以更好地监控和调试应用程序。本文将详细介绍如何在 Django 项目中实现日志文件分割、日志级别控制以及多环境日志配置,并结合最佳实践和代码示例,…...

[笔记] 极狐GitLab实例 : 手动备份步骤总结

官方备份文档 : 备份和恢复极狐GitLab 一. 要求 为了能够进行备份和恢复&#xff0c;请确保您系统已安装 Rsync。 如果您安装了极狐GitLab&#xff1a; 如果您使用 Omnibus 软件包&#xff0c;则无需额外操作。如果您使用源代码安装&#xff0c;您需要确定是否安装了 rsync。…...

php代码审计2 piwigo CMS in_array()函数漏洞

php代码审计2 piwigo CMS in_array()函数漏洞 一、目的 本次学习目的是了解in_array()函数和对项目piwigo中关于in_array()函数存在漏洞的一个审计并利用漏洞获得管理员帐号。 二、in_array函数学习 in_array() 函数搜索数组中是否存在指定的值。 in_array($search,$array…...

随机矩阵投影长度保持引理及其证明

原论文中的引理 2 \textbf{2} 2 1. \textbf{1. } 1. 引理 1 \textbf{1} 1(前提之一) 1.1. \textbf{1.1. } 1.1. 引理 1 \textbf{1} 1的内容 &#x1f449;前提&#xff1a; X ∼ N ( 0 , σ ) X\sim{}N(0,\sigma) X∼N(0,σ)即 f ( x ) 1 2 π σ e – x 2 2 σ 2 f(x)\text{}…...

蓝桥杯真题 - 三国游戏 - 题解

题目链接&#xff1a;https://www.lanqiao.cn/problems/3518/learning/ 个人评价&#xff1a;难度 2 星&#xff08;满星&#xff1a;5&#xff09; 前置知识&#xff1a;贪心 整体思路 先假设魏蜀吴中的某一个势力最终获胜的情况下&#xff0c;如何求出事件发生的最大数量&a…...

Spring 源码学习(七)——注解后处理器-2

五 InitDestroyAnnotationBeanPostProcessor 类 1 属性 InitDestroyAnnotationBeanPostProcessor 类用于处理初始化与销毁注解&#xff1b;其中第一个属性为用于标识初始化方法与销毁方法注解类型的 initAnnotationType 与 destroyAnnotationType 属性、还有一个用于标识执行顺…...

即梦(Dreamina)技术浅析(一)

1.技术架构与核心组件 2.生成模型的具体实现 3.多模态融合技术 4.训练数据与模型优化 5.用户交互与创作流程 6.技术挑战与解决方案 7.未来发展方向 1. 技术架构与核心组件 即梦的技术架构可以分为以下几个核心组件: 1.1 前端用户界面(UI) 功能模块: 文字输入框:用…...

Spring MVC(二)

介绍 Cookie 与 Session Session 类似哈希表&#xff0c;存储了一些键值对结构&#xff0c;Key 就是 SessionID&#xff0c;Vaule 就是用户信息&#xff0c;客户端发起会话的时候&#xff0c;服务器一旦接收&#xff0c;就会创建会话【也就是 Session】&#xff0c;通过 Sessi…...

java求职学习day15

多线程 1 基本概念 1.1 程序和进程的概念 &#xff08;1&#xff09;程序 - 数据结构 算法&#xff0c;主要指存放在硬盘上的可执行文件。 &#xff08;2&#xff09;进程 - 主要指运行在内存中的可执行文件。 &#xff08;3&#xff09;目前主流的操作系统都支持多进程&a…...

Typesrcipt泛型约束详细解读

代码示例&#xff1a; // 如果我们直接对一个泛型参数取 length 属性, 会报错, 因为这个泛型根本就不知道它有这个属性 (() > {// 定义一个接口,用来约束将来的某个类型中必须要有length这个属性interface ILength{// 接口中有一个属性lengthlength:number}function getLen…...

[操作系统] 进程地址空间管理

虚拟地址空间的初始化 缺页中断 缺页中断的概念 缺页中断&#xff08;Page Fault Interrupt&#xff09; 是指当程序访问的虚拟地址在页表中不存在有效映射&#xff08;即该页未加载到内存中&#xff09;时&#xff0c;CPU 会发出一个中断信号&#xff0c;请求操作系统加载所…...

【fly-iot飞凡物联】(20):2025年总体规划,把物联网整套技术方案和实现并落地,完成项目开发和课程录制。

前言 fly-iot飞凡物联专栏&#xff1a; https://blog.csdn.net/freewebsys/category_12219758.html 1&#xff0c;开源项目地址进行项目开发 https://gitee.com/fly-iot/fly-iot-platform 完成项目开发&#xff0c;接口开发。 把相关内容总结成文档&#xff0c;并录制课程。…...

14-6-1C++STL的list

(一&#xff09;list容器的基本概念 list容器简介&#xff1a; 1.list是一个双向链表容器&#xff0c;可高效地进行插入删除元素 2.list不可以随机存取元素&#xff0c;所以不支持at.(pos)函数与[ ]操作符 &#xff08;二&#xff09;list容器头部和尾部的操作 list对象的默…...

vue2和vue3指令

Vue 2 和 Vue 3 的指令系统非常相似&#xff0c;但 Vue 3 在指令方面进行了优化和扩展。以下是 Vue 2 和 Vue 3 中指令的对比&#xff1a; 1. 通用指令 这些指令在 Vue 2 和 Vue 3 中都可以使用&#xff0c;功能一致&#xff1a; 指令说明v-bind绑定 HTML 属性或组件 propsv-…...

求整数的和与均值(信息学奥赛一本通-1061)

【题目描述】 读入n(1≤n≤10000)个整数&#xff0c;求它们的和与均值。 【输入】 输入第一行是一个整数n&#xff0c;表示有n个整数。 第2~n1行每行包含1个整数。每个整数的绝对值均不超过10000。 【输出】 输出一行&#xff0c;先输出和&#xff0c;再输出平均值(保留到小数点…...

CodeForces 611:New Year and Domino ← 二维前缀和

【题目来源】 https://codeforces.com/contest/611/problem/C 【题目描述】 They say "years are like dominoes, tumbling one after the other". But would a year fit into a grid? I dont think so. Limak is a little polar bear who loves to play. He has r…...

【ROS2】RViz2界面类 VisualizationFrame 详解

1、简述 VisualizationFrame 继承自 QMainWindow 和 WindowManagerInterface; 窗口顶部是常规布局:菜单栏 和 工具栏 窗口中心是 RenderPanel,用来渲染3D画面 周围是dock区域,包括:DisplaysPanel、ViewsPanel、TimePanel、SelectionPanel 和 ToolPropertiesPanel Windo…...

梯度下降法 (Gradient Descent) 算法详解及案例分析

梯度下降法 (Gradient Descent) 算法详解及案例分析 目录 梯度下降法 (Gradient Descent) 算法详解及案例分析1. 引言2. 梯度下降法 (Gradient Descent) 算法原理2.1 基本概念2.2 算法步骤2.3 梯度下降法的变种3. 梯度下降法的优势与局限性3.1 优势3.2 局限性4. 案例分析4.1 案…...

【Flutter】旋转元素(Transform、RotatedBox )

这里写自定义目录标题 Transform旋转元素可以改变宽高约束的旋转 - RotatedBox Transform旋转元素 说明&#xff1a;Transform旋转操作改变了元素的方向&#xff0c;但并没有改变它的布局约束。因此&#xff0c;虽然视觉上元素看起来是旋转了&#xff0c;但它仍然遵循原始的宽…...

大数运算之C语言实现

一、 前言 在我们代码编程过程中&#xff0c;我们经常需要处理各种规模的数值。从日常工作中的一些简单算术在到科学研究中的复杂计算&#xff0c;数字无处不在。然而&#xff0c;当数值变的异常庞大时&#xff0c;就需要用到大数运算来进行实现。本文我们将介绍大数运算的基本…...

三高“高性能、高并发、高可靠”系统架构设计系列文章

目录 高并发系统的艺术&#xff1a;如何在流量洪峰中游刃有余 《数据密集型应用系统设计》读后感与高并发高性能实践案例 系统稳定性与高可用保障的几种思路 软件系统限流的底层原理解析 技术解决方案调研 延迟队列调研 重试调研 异步回调调研 分库分表调研 分布式事…...

Java设计模式 十八 状态模式 (State Pattern)

状态模式 (State Pattern) 状态模式是一种行为型设计模式&#xff0c;它允许对象在其内部状态改变时改变其行为。状态模式让一个对象在其状态改变时&#xff0c;其行为也随之改变&#xff0c;看起来就像是改变了对象的类。通过将状态的变化封装到不同的状态对象中&#xff0c;…...

Django创建纯净版项目并启动

1.Django的基本目录结构 2. 创建app项目 python manage.py startapp user# python manage.py 是固定的&#xff0c;代表python脚本&#xff0c;主要用于django中的项目管理 # startapp 创建app # user 你的app名字&#xff0c;也就是功能模块名称3.数据库 进入settings.…...

[b01lers2020]Life on Mars1

打开题目页面如下 看了旁边的链接&#xff0c;也没有什么注入点&#xff0c;是正常的科普 利用burp suite抓包&#xff0c;发现传参 访问一下 http://5edaec92-dd87-4fec-b0e3-501ff24d3650.node5.buuoj.cn:81/query?searchtharsis_rise 接下来进行sql注入 方法一&#xf…...

element-plus 的table section如何实现单选

如果是单选那么全新的按钮应该隐藏或者不可编辑的状态。但是我没找到改变成不可编辑的方法&#xff0c;只能采取隐藏 <template><!-- 注意要包一层div根元素&#xff0c;否则css样式可能会不生效&#xff0c;原因不详 --><div><el-table ref"proTab…...

利用Qt5.15.2编写Android程序时遇到的问题及解决方法

文章目录 背景1.文件读写 背景 目前我用的是Qt5.15.2来编写Qt程序&#xff0c;环境的配置看我这篇文章【Qt5.15.2配置Android开发环境】 项目中的一些配置的截图&#xff1a; 1.文件读写 假如直接用 QFileDialog::getExistingDirectory来获取路径的话&#xff0c;会得到类…...

奇怪的单词(快速扩张200个单词)

这是一些非常奇怪的单词&#xff1a; screw n.螺丝&#xff1b;螺丝钉 screwdriver n.起子&#xff0c;螺丝刀&#xff0c;改锥 copulation n.连接 copulate a.配合的 bonk n.撞击&#xff1b;猛击 v.轻击&#xff1b;碰撞ebony n.黑檀couple n.夫妇blonde n.金发女郎intimacy…...

three.js+WebGL踩坑经验合集(4.1):THREE.Line2的射线检测问题(注意本篇说的是Line2,同样也不是阈值方面的问题)

上篇大家消化得如何了&#xff1f; 笔者说过&#xff0c;1级编号不同的两篇博文相对独立&#xff0c;所以这里笔者还是先给出完整代码&#xff0c;哪怕跟&#xff08;3&#xff09;没有太大区别。 这里我们把线的粗细调成5&#xff08;排除难选中的因素&#xff09;&#xff…...

postgresql根据主键ID字段分批删除表数据

生产环境针对大表的处理相对比较麻烦。 方案1、直接truncate&#xff0c;可能会遇到系统卡主的情况&#xff0c;因为truncate的过程中会对表进行加锁&#xff0c;会导致数据不能正常的写入 方案2、创建一个同结构的表结构&#xff0c;rename旧表&#xff0c;不停业务rename表担…...

NIO 和 Netty 在 Spring Boot 中的集成与使用

Netty到底是个啥&#xff0c;有啥子作用 1. Netty 的本质&#xff1a;对 NIO 的封装 NIO 的原生问题&#xff1a; Java 的 NIO 提供了非阻塞 I/O 和多路复用机制&#xff0c;但其使用较为复杂&#xff08;如 Selector、Channel、Buffer 的配置和管理&#xff09;。开发者需要自…...

【AI论文】Sigma:对查询、键和值进行差分缩放,以实现高效语言模型

摘要&#xff1a;我们推出了Sigma&#xff0c;这是一个专为系统领域设计的高效大型语言模型&#xff0c;其独特之处在于采用了包括DiffQKV注意力机制在内的新型架构&#xff0c;并在我们精心收集的系统领域数据上进行了预训练。DiffQKV注意力机制通过根据查询&#xff08;Q&…...

ThinkPHP 8请求处理-获取请求对象与请求上下文

【图书介绍】《ThinkPHP 8高效构建Web应用》-CSDN博客 《2025新书 ThinkPHP 8高效构建Web应用 编程与应用开发丛书 夏磊 清华大学出版社教材书籍 9787302678236 ThinkPHP 8高效构建Web应用》【摘要 书评 试读】- 京东图书 使用Composer初始化ThinkPHP 8应用_thinkphp8 compos…...

【设计模式】JAVA 策略 工厂 模式 彻底告别switch if 等

【设计模式】JAVA 策略 工厂 模式 彻底告别switch if 等 目录 【设计模式】JAVA 策略 工厂 模式 彻底告别switch if 等 优势 适用场景 项目结构 关键代码 优势 消除 switch&#xff1a;将分支逻辑分散到独立的策略类中。 开闭原则&#xff1a;新增类型只需添加新的 TypeHa…...

Pyecharts之词云图、面积图与堆叠面积图

在数据可视化的精彩世界里&#xff0c;我们可以运用各种各样的图表来展现数据的魅力&#xff0c;帮助我们更好地理解和分析数据。Pyecharts 作为一款功能强大的数据可视化工具&#xff0c;为我们提供了丰富的图表类型&#xff0c;今天我们将深入探讨词云图、面积图和堆叠面积图…...

SpringBoot3+Vue3开发学生选课管理系统

功能介绍 分三个角色登录&#xff1a;学生登录&#xff0c;老师登录&#xff0c;教务管理员登录&#xff0c;不同用户功能不同&#xff01; 1.学生用户功能 选课记录&#xff0c;查看选课记录&#xff0c;退选。选课管理&#xff0c;进行选课。通知管理&#xff0c;查看通知消…...

71.在 Vue 3 中使用 OpenLayers 实现按住 Shift 拖拽、旋转和缩放效果

前言 在前端开发中&#xff0c;地图功能是一个常见的需求。OpenLayers 是一个强大的开源地图库&#xff0c;支持多种地图源和交互操作。本文将介绍如何在 Vue 3 中集成 OpenLayers&#xff0c;并实现按住 Shift 键拖拽、旋转和缩放地图的效果。 实现效果 按住 Shift 键&#…...

Mybatis——sql映射文件中的增删查改

映射文件内的增删查改 准备工作 准备一张数据表&#xff0c;用于进行数据库的相关操作。新建maven工程&#xff0c; 导入mysql-connector-java和mybatis依赖。新建一个实体类&#xff0c;类的字段要和数据表的数据对应编写接口编写mybatis主配置文件 public class User {priva…...

Git进阶笔记系列(01)Git核心架构原理 | 常用命令实战集合

读书笔记&#xff1a;卓越强迫症强大恐惧症&#xff0c;在亲子家庭、职场关系里尤其是纵向关系模型里&#xff0c;这两种状态很容易无缝衔接。尤其父母对子女、领导对下属&#xff0c;都有望子成龙、强将无弱兵的期望&#xff0c;然而在你的面前&#xff0c;他们才是永远强大的…...