springboot集成websokcet+H5开发聊天原型(二)

本文没有写完~~~~

聊天相关数据结构: 

我们初步设计了如下几个数据结构。

//存放 sessionId 与 userId 的map

private Map<String,String> sessionId_userId =new HashMap<>();

// 用于存储用户与群组的关联关系,键为用户ID,值为群组ID列表 一个用户可以加入多个群组 它是一个Map,键是用户ID,值是群组ID列表

private Map<String, List<String>> userGroups = new HashMap<>();

// 用于存储群组信息,键为群组ID,值包含在线用户会话列表和历史消息列表
private Map<String, GroupInfo> groupInfos = new HashMap<>();用户通过socket和服务端连接的时候,都会传递 
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {LOGGER.info("WebSocket收到的消息: {}", message.getPayload());// 将消息反序列化,假设消息是JSON格式,这里解析为Message对象(下面定义)Message msg = objectMapper.readValue(message.getPayload().toString(), Message.class);String groupId = msg.getGroupId();String userId=msg.getUserId();int flag=this.checkUserIdAndSessionId(session.getId(),userId);  //检查userId和sessionId是否匹配//flag==0 说明userId和sessionId匹配 ,不做更多的操作 直接执行下面的代码if(flag==2){   //userId一致 但是 sessionId不一致,说明用户重新建立了session,要把原来该用户相关的session等全部删除掉//找到这个用户下原来所有的session,然后全部删除掉for (Map.Entry<String, String> entry : sessionId_userId.entrySet()) {String storedSessionId = entry.getKey();String storedUserId = entry.getValue();if (storedUserId.equals(userId)) {sessionId_userId.remove(storedSessionId);}//by userId remove all the groupInfoList<String> groupIds = userGroups.get(userId);if (groupIds!= null) {for (String groupId1 : groupIds) {GroupInfo groupInfo = groupInfos.get(groupId1);if (groupInfo!= null) {groupInfo.removeSession(session);}}userGroups.remove(userId);}}}else if(flag==3){  //userId不存在  session不存在 ,用户第一次建立连接//do nothing   放在这里就是为了说明flag==3的情况}if(flag==2 || flag==3){sessionId_userId.put(session.getId(),userId);    //sessionId 与 userId 建立映射  是1对1的关系List<String> groupIds = userGroups.computeIfAbsent(userId, k -> new ArrayList<>());  // 获取用户的群组ID列表groupIds.add(groupId);}GroupInfo groupInfo = groupInfos.get(groupId);if (groupInfo == null) {// 如果群组信息不存在,则创建新的群组信息,并添加当前用户的WebSocketSessiongroupInfo = new GroupInfo();groupInfo.addSession(session);groupInfos.put(groupId, groupInfo);// 同时,假设这里从WebSocket连接的属性或者请求参数中获取用户ID(实际需按业务逻辑调整获取方式)//String userId = (String) session.getAttributes().get("userId");
//            List<String> groupIds = userGroups.computeIfAbsent(userId, k -> new ArrayList<>());  // 获取用户的群组ID列表
//            groupIds.add(groupId);}else {groupInfo.addSession(session);  //addSession()方法会检查是否已经存在,如果存在就不会再添加}// 将消息添加到群组历史消息列表groupInfo.addHistoryMessage(msg);// 向群组内所有在线用户发送消息List<WebSocketSession> sessions = groupInfo.getSessions();for (WebSocketSession s : sessions) {try {s.sendMessage(new TextMessage(objectMapper.writeValueAsString(msg)));} catch (IOException e) {LOGGER.error("无法发送WebSocket消息", e);}}}


 

uniapp端页面:

<template><view class="chat-room"><!-- 聊天记录 --><scroll-view scroll-y="true" class="message-list"><view v-for="(message, index) in messages" :key="index" class="message-item"><view v-if="message.type === 'text'" class="text-message"><!--    <view class="avatar">{{ message.senderAvatar }}</view> --><view class="text">{{ message.content }}</view></view><view v-else-if="message.type === 'image'" class="image-message"><image :src="message.content" class="message-image" @click="previewImage(message.content)"></image></view></view></scroll-view><!-- 输入框 --><view class="input-area"><input v-model="inputContent" placeholder="输入内容" class="input" /><button @click="sendMessage">发送</button></view></view>
</template><script>
export default {data() {return {messages: [], // 聊天记录inputContent: '', // 输入框内容socketOpen: false, // WebSocket连接状态socket: null, // WebSocket对象};},methods: {// 初始化WebSocket连接initWebSocket() {uni.setStorageSync('userId',1);  // only testuni.setStorageSync('groupIds',2);  // only testconst userId = uni.getStorageSync('userId');const groupIds = uni.getStorageSync('groupIds');console.log(groupIds);// /wechat/client/chatthis.socket = uni.connectSocket({url: 'ws://127.0.0.1:7877/chat/websocket',data: {userId: userId,groupIds: groupIds},success: () => {console.log('WebSocket连接成功');this.socketOpen = true;},fail: () => {console.error('WebSocket连接失败');},});// 监听WebSocket消息this.socket.onMessage((res) => {const message = JSON.parse(res.data);this.messages.push(message); // 将新消息添加到聊天记录中this.$forceUpdate(); // 强制更新视图,确保新消息显示});// 监听WebSocket连接关闭this.socket.onClose(() => {console.log('WebSocket连接关闭');this.socketOpen = false;});},// 发送消息
sendMessage() {if (this.inputContent.trim() === '') {uni.showToast({title: '请输入内容',icon: 'none',});return;}const message = {type: 'text', // 消息类型,可以是text或image,这里发送文字消息示例,发送图片时修改相应字段groupId: uni.getStorageSync('groupIds'), // 从本地存储获取当前所在群组ID(需按实际情况调整获取方式)sender: uni.getStorageSync('userId'), // 从本地存储获取用户ID(需按实际情况调整获取方式)content: this.inputContent};// 通过WebSocket发送消息(或HTTP请求,根据后端接口决定)if (this.socketOpen) {this.socket.send({data: JSON.stringify(message)});} else {//todo}
},// 预览图片previewImage(url) {uni.previewImage({current: url, // 当前显示图片的http链接urls: [url], // 需要预览的图片http链接列表});},},mounted() {// 页面加载时初始化WebSocket连接this.initWebSocket();// 可以从服务器获取历史聊天记录并初始化messages数组(根据需求实现)},
};
</script><style>
.chat-room {padding: 10px;
}.message-list {height: 500px; /* 根据需要调整高度 */border-bottom: 1px solid #ccc;padding-right: 10px; /* 留出空间给滚动条 */overflow-y: auto;
}.message-item {margin-bottom: 10px;display: flex;align-items: center;
}.avatar {width: 40px;height: 40px;border-radius: 50%;margin-right: 10px;
}.text-message .text {background-color: #fff;padding: 5px 10px;border-radius: 5px;max-width: 60%; /* 根据需要调整宽度 */word-wrap: break-word; /* 防止长文本溢出 */
}.image-message .message-image {width: 100px;height: 100px;object-fit: cover;border-radius: 5px;
}.input-area {display: flex;margin-top: 10px;
}.input {flex: 1;padding: 5px;border: 1px solid #ccc;border-radius: 5px;
}button {padding: 5px 10px;margin-left: 10px;border: none;background-color: #1aad19;color: #fff;border-radius: 5px;
}
</style>

原型效果:

后期再补充~~~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/500499.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue实现下拉多选、可搜索、全选功能

最后的效果就是树形的下拉多选&#xff0c;可选择任意一级选项&#xff0c;下拉框中有一个按钮可以实现全选&#xff0c;也支持搜索功能。 在mounted生命周期里面获取全部部门的数据&#xff0c;handleTree是讲接口返回的数据整理成树形结构&#xff0c;可以自行解决 <div c…

Pytorch | 利用DTA针对CIFAR10上的ResNet分类器进行对抗攻击

Pytorch | 利用DTA针对CIFAR10上的ResNet分类器进行对抗攻击 CIFAR数据集DTA介绍算法流程 DTA代码实现DTA算法实现攻击效果 代码汇总dta.pytrain.pyadvtest.py 之前已经针对CIFAR10训练了多种分类器&#xff1a; Pytorch | 从零构建AlexNet对CIFAR10进行分类 Pytorch | 从零构建…

攻防世界web第六题upload1

这是题目&#xff0c;可以看出是个上传文件的题目&#xff0c;考虑文件上传漏洞&#xff0c;先随便上传一个文件试试&#xff0c;要求上传的是图片。 可以看到上传成功。 考虑用一句话木马解决&#xff0c;构造文件并修改后缀为jpg,然后上传。 <?php eval($_POST[attack])…

python数据分析:使用pandas库读取和编辑Excel表

使用 Pandas&#xff0c;我们可以轻松地读取和写入Excel 文件&#xff0c;之前文章我们介绍了其他多种方法。 使用前确保已经安装pandas和 openpyxl库&#xff08;默认使用该库处理Excel文件&#xff09;。没有安装的可以使用pip命令安装&#xff1a; pip install pandas ope…

SpringCloud源码分析-LoadBalancer

# 负载均衡缓存 org.springframework.cloud.loadbalancer.cache.DefaultLoadBalancerCache # 缓存服务实例提供 org.springframework.cloud.loadbalancer.core.CachingServiceInstanceListSupplier 负载均衡实例中没有机器列表时&#xff0c;都会查询一次org.springframewor…

Postman[2] 入门——界面介绍

可参考官方 文档 Postman 导航 | Postman 官方帮助文档中文版Postman 拥有各种工具、视图和控件&#xff0c;帮助你管理 API 项目。本指南是对 Postman 主要界面区域的高级概述&#xff1a;https://postman.xiniushu.com/docs/getting-started/navigating-postman 1. Header&a…

大数据技术-Hadoop(三)Mapreduce的介绍与使用

目录 一、概念和定义 二、WordCount案例 1、WordCountMapper 2、WordCountReducer 3、WordCountDriver 三、序列化 1、为什么序列化 2、为什么不用Java的序列化 3、Hadoop序列化特点&#xff1a; 4、自定义bean对象实现序列化接口&#xff08;Writable&#xff09; 4…

Python爬取城市天气信息,并存储到csv文件中

1.爬取的网址为&#xff1a;天气网 (weather.com.cn) 2.需要建立Weather.txt文件&#xff0c;并在里面加入如下形式的字段&#xff1a; 101120701济宁 101010100北京 3.代码运行后&#xff0c;在命令行输入Weather.txt文件中添加过的城市&#xff0c;如&#xff1a;济宁。 …

CentOS Stream 9 安装 JDK

安装前检查 java --version注&#xff1a;此时说明已安装过JDK&#xff0c;否则为未安装。如若已安装过JDK可以跳过安装步骤直接使用&#xff0c;或者先卸载已安装的JDK版本重新安装。 安装JDK 官网下载地址&#xff1a;https://www.oracle.com/java/technologies/downloads…

win11 vs2022 opencv 4.10使用vs Image Watch插件实时可视化内存mat对象

这个本来是非开源工业软件HALCON的一个功能&#xff0c;方便提升图像识别开发效率。原以为opencv没有&#xff0c;需要通过进程间共享内存的方式去实现。 结果在官网帮助文档中发现已经提供了。 opencv 4.10帮助文档https://docs.opencv.org/4.10.0/index.htmlOpenCV Tutorial…

C#Halcon深度学习预热与否的运行时间测试

在深度学习推理应用阶段&#xff0c;涉及到提速&#xff0c;绕不开一个关键词“预热”。 在其他地方的“预热”&#xff0c;预先加热到指定的温度。通常指预习准备做某一样事时&#xff0c;为此做好准备。 而在深度学习推理应用阶段涉及的预热通常是指GPU预热&#xff0c;GPU在…

STM32-笔记18-呼吸灯

1、实验目的 使用定时器 4 通道 3 生成 PWM 波控制 LED1 &#xff0c;实现呼吸灯效果。 频率&#xff1a;2kHz&#xff0c;PSC71&#xff0c;ARR499 利用定时器溢出公式 周期等于频率的倒数。故Tout 1/2KHZ&#xff1b;Ft 72MHZ PSC71&#xff08;喜欢设置成Ft的倍数&…

OCR实践-问卷表格统计

前言 书接上文 OCR实践—PaddleOCROCR实践-Table-Transformer 本项目代码已开源 放在 Github上&#xff0c;欢迎参考使用&#xff0c;Star https://github.com/caibucai22/TableAnalysisTool 主要功能说明&#xff1a;对手动拍照的问卷图片进行统计分数&#xff08;对应分数…

使用pandas把数据库中的数据转成csv文件

使用pandas把数据库中的数据转成csv文件 1、效果图 2、流程 1、连接数据库,获取数据 2、把一些中文字符转成gbk,忽略掉无法转化的 3、把数据转成csv 3、代码 import pymysql import pandas as pddef get_database(databasename):

windows下vscode使用msvc编译器出现中文乱码

文章目录 [toc]1、概述2、修改已创建文件编码3、修改vscode默认编码 更多精彩内容&#x1f449;内容导航 &#x1f448;&#x1f449;C &#x1f448;&#x1f449;开发工具 &#x1f448; 1、概述 在使用MSVC编译器时&#xff0c;出现中文报错的问题可能与编码格式有关。UTF-…

传统听写与大模型听写比对

在快节奏的现代生活中&#xff0c;听写技能仍然是学习语言和提升认知能力的重要环节。然而&#xff0c;传统的听写练习往往枯燥乏味&#xff0c;且效率不高。现在&#xff0c;随着人工智能技术的发展&#xff0c;大模型听写工具的问世&#xff0c;为传统听写带来了革命性的变革…

前端页面上传文件:解决 ERR_UPLOAD_FILE_CHANGED

文章目录 引言I 问题 ERR_UPLOAD_FILE_CHANGED问题重现步骤原因II 解决方法将文件转换为base64再转回file检测文件内容是否发生变更III 知识扩展发送一个包含文件和文本的multipart/form-data请求签名优化引言 文件上传应用场景:船舶设备的新增导入(基础信息:出厂编号)船舶…

图文教程:使用PowerDesigner导出数据库表结构为Word/Html文档

1、第一种情况-无数据库表&#xff0c;但有数据模型 1.1 使用PowerDesigner已完成数据建模 您已经使用PowerDesigner完成数据库建模&#xff0c;如下图&#xff1a; 1.2 Report配置和导出 1、点击&#xff1a;Report->Reports&#xff0c;如下图&#xff1a; 2、点击&…

vscode 多项目冲突:进行 vscode 工作区配置

问题&#xff1a;多个项目&#xff0c;每次打开会因为配置问题/包版本冲突&#xff0c;花费过长时间。 解决&#xff1a;可以通过启用工作区&#xff0c;使得各个项目的开发环境隔离。 vscode官网 对此有两种方法&#xff1a;方法一&#xff1a;启用工作区&#xff08;workspa…

试用ChatGPT的copilot编写一个程序从笔记本电脑获取语音输入和图像输入并调用开源大模型进行解析

借助copilot写代码和自己手写代码的开发过程是一样的。 首先要有明确的开发需求&#xff0c;开发需求越详细&#xff0c;copilot写出的代码才能越符合我们的预期。 其次&#xff0c;有了明确的需求&#xff0c;最好先做下需求拆解&#xff0c;特别是对于比较复杂的应用&#xf…