加载指定会话最近消息
加载指定会话最近消息
前言
上一集我们就把三个标签页的加载列表的任务给完成啦!那么我们这一集就来完成加载指定绘画最近消息的任务。
需求分析
我们点击了某个会话之后,我们就会去显示我们的会话的最近的N条消息。请看下图。

我们这里涉及到两个区域,一个是中间的区域,一个是右边的消息展示区域。
当然这里我们只展示N条消息记录,我们不多去展示,不然影响我们的程序的效率和用户的体验感。这里和我们的返回历史消息记录查询是完全不同的东西!
我们还是先来看一下我们的URL
![]()
再来看一眼我们的请求和响应的定义。

这就是我们这一集的任务要求!
客户端
常规操作,分两端,这里是客户端的代码操作!
loadRecentMessage
SessionItem::active
我们要考虑这个加载指定会话的最近消息要在哪里进行调用?
我们应该在这个会话被点击的时候就加载这个函数,那么我们就应该把这个函数放到我们SessionItem的active这个成员函数当中。
由于又要涉及到我们主界面的消息展示区,那么这个函数必须放置在我们的主界面的代码当中。
那么我们就要获取到MainWidget的实例,之后调用这个函数。
void SessionItem::active()
{LOG() << "点击 SessionItem 触发的逻辑 chatSessionId=" << chatSessionId;//加载会话历史消息会涉及到当前内存的数据操作,又会涉及到网络通信,还会涉及到界面的变更//使用到主窗口的方法进行调用MainWidget* mainWidget = MainWidget::getInstance();mainWidget->loadRecentMessage(chatSessionId);}
loadRecentMessage的具体实现
我们需要传入需要加载的会话id,因为我们不是加载整个最近消息,所以我们要去传入会话id。
那么我们还是分为了两个部分,一个是从内存进行加载,一个是从网络进行加载。
我们判定的是这个会话的最近消息列表,而不是整个最近的消息列表,所以我们应该去访问key为chatSessionId的最近消息列表。我们判定整个会话的最近消息列表是没有什么用的!
getRecentMessageList
QList<Message> *DataCenter::getRecentMessageList(const QString &chatSessionId)
{if(!recentMessage->contains(chatSessionId)){return nullptr;}return &(*recentMessage)[chatSessionId];
}
我们先完成这个判定的函数,这里我们要先去访问这个哈希表是否存在这个chatSessionId的列表,如果没有就直接返回一个nullptr即可,如果有,就返回这个列表的指针即可。
void MainWidget::loadRecentMessage(const QString &chatSessionId)
{//先判定本地是否存有数据DataCenter* dataCenter = DataCenter::getInstance();//判定的是这个会话的最近消息列表,不是整个最近消息列表if(dataCenter->getRecentMessageList(chatSessionId) != nullptr){//本地数据加载updateRecentMessage(chatSessionId);}else{//网络数据加载connect(dataCenter, &DataCenter::getRecentMessageListDone, this, &MainWidget::updateRecentMessage, Qt::UniqueConnection);dataCenter->getRecentMessageListAsync(chatSessionId);}}
本地数据加载
updateRecentMessage
这个代码也是分为两个部分,我们先讲这个本地数据加载的内容。
我们这里不要忘了,这个内容是展示到我们的消息展示区的,不是我们的好友列表上!
我们先从DataCenter中获取这个列表,之后清空我们整个消息展示区,之后头插我们的消息内容。我们判定我们的消息是靠左还是靠右,只需要去看这个消息的发送者的userId,和我们DataCenter里面保存的Myself的userId即可。
之后我们要设置我们的会话标题,再把我们当前选中的会话保存到我们的DataCenter当中。最后我们再来一个滚动条设置滑动到我们的消息的末尾即可。
void MainWidget::updateRecentMessage(const QString &chatSessionId)
{//获取最近的消息列表DataCenter* dataCenter = DataCenter::getInstance();auto* recentMessageList = dataCenter->getRecentMessageList(chatSessionId);//这里不要把内容添加到会话了,这里是要添加到消息展示区上//清空原有界面上的消息列表messageShowArea->clear();//遍历//要先看到最近消息,那就是用头插for(int i = recentMessageList->size() - 1; i >= 0; --i){const Message& message = recentMessageList->at(i);bool isLeft = message.sender.userId != dataCenter->getMyself()->userId;//用这个消息的发送者的用户id和数据中心的自身信息的用户id对比即可messageShowArea->addFrontMessage(isLeft, message);}//设置会话标题ChatSessionInfo* chatSessionInfo = dataCenter->findChatSessionById(chatSessionId);if(chatSessionInfo != nullptr){//把会话的名称显示到界面上sessionTitleLabel->setText(chatSessionInfo->chatSessionName);}//保存当前选中的会话dataCenter->setCurrentChatSessionId(chatSessionId);//自动把滚动条滚动到末尾,就可以先看到最近的第一条消息messageShowArea->scrollToEnd();}
这里我们还要去是完成获取会话消息,保存当前选中会话,以及自动滑动滚动条到末尾的三个重要函数。
findChatSessionById
我们通过chatSessionId从DataCenter当中寻找会话列表中的指定会话的信息。
ChatSessionInfo *DataCenter::findChatSessionById(const QString &chatSessionId)
{//判断会话列表是否为空if(chatSessionList == nullptr){return nullptr;}for(auto& info : *chatSessionList){if(info.chatSessionId == chatSessionId){return &info;}}//没找到return nullptr;
}
set/getCurrentChatSessionId
void DataCenter::setCurrentChatSessionId(const QString &chatSessionId)
{this->currentChatSessionId = chatSessionId;
}const QString &DataCenter::getCurrentChatSessionId()
{return currentChatSessionId;
}
scrollToEnd
void MessageShowArea::scrollToEnd()
{//获取垂直滚动条//获取到最大值//延时操作QTimer* timer = new QTimer();connect(timer, &QTimer::timeout, this, [=](){int maxValue = this->verticalScrollBar()->maximum();this->verticalScrollBar()->setValue(maxValue);timer->stop();timer->deleteLater();});timer->start(500);
}
使用延时操作,等会话里的消息都加载到界面上,我们再去获取到我们的具体滚动区域最大值,之后滑动即可。
这样我们就可以通过本地数据进行加载我们指定会话的最近消息列表了!
网络通信加载
getRecentMessageListAsync
我们不仅仅要传到NetClient的有loginSessionId,我们还有指定的chatSessionId。
void DataCenter::getRecentMessageListAsync(const QString &chatSessionId)
{netClient.getRecentMessageList(loginSessionId, chatSessionId);
}
getRecentMessageList
我们还是老步骤啊,构造请求body,序列化,之后发送请求到我们指定的URL,之后处理我们的响应,之后就是把我们的数据放置到我们的数据中心,之后发送信号,之后触发我们的信号槽从本地数据再获取数据即可!
void NetClient::getRecentMessageList(const QString &loginSessionId, const QString &chatSessionId)
{//构造请求bodybite_im::GetRecentMsgReq req;req.setRequestId(makeRequestId());req.setChatSessionId(chatSessionId);req.setMsgCount(50);//固定获取50条req.setSessionId(loginSessionId);//序列化QByteArray body = req.serialize(&serializer);LOG() << "[获取最近消息] 发送请求 requestId=" << req.requestId() << ", loginSessionId=" << loginSessionId;//发送http请求QNetworkReply* resp = this->sendHttpRequest("/service/message_storage/get_recent", body);//处理响应connect(resp, &QNetworkReply::finished, this, [=](){//解析响应bool ok = false;QString reason;auto pbResp = this->handleHttpResponse<bite_im::GetRecentMsgRsp>(resp, &ok, &reason);//判定响应是否okif(!ok){LOG() << "[获取最近消息] 失败! requestId=" << req.requestId() << ", reason=" << reason;return;}//设置到DataCenter中dataCenter->resetRecentMessageList(chatSessionId, pbResp);//发送信号告知界面进行更新emit dataCenter->getRecentMessageListDone(chatSessionId);});
}
resetRecentMessageList
这里我们不需要判定是否为空,因为哈希的特性!我们不存在就会直接创建,我们记得清空一下这个指定会话的最近消息列表,之后通过遍历,我们把获得的数据设置到我们的recentMessage,记住一定要用引用!!!
void DataCenter::resetRecentMessageList(const QString &chatSessionId, std::shared_ptr<bite_im::GetRecentMsgRsp> resp)
{//哈希的特性存在就使用,不存在就创建新的,清空QList<Message>& messageList = (*recentMessage)[chatSessionId];messageList.clear();//遍历for(auto& m : resp->msgList()){Message message;message.load(m);messageList.push_back(message);}
}
之后触发我们的信号就可以返回到我们的主界面那边了。
connect(dataCenter, &DataCenter::getRecentMessageListDone, this, &MainWidget::updateRecentMessage, Qt::UniqueConnection);
记得我们的第五个参数,是为了防止一个信号触发我们多个这个槽函数。
到这里我们的客户端就完成了,我们继续完成测试服务端!
测试服务端
配置路由
httpServer.route("/service/message_storage/get_recent", [=](const QHttpServerRequest& req){return this->getRecent(req);});
基本操作,我们直接到getRecent函数当中!
getRecent
也是基本操作,我们构造了一堆假数据放置到我们的界面上。
QHttpServerResponse HttpServer::getRecent(const QHttpServerRequest &req)
{//解析请求bite_im::GetRecentMsgReq pbReq;pbReq.deserialize(&serializer, req.body());LOG() << "[REQ 获取最近消息列表] requestId=" << pbReq.requestId() << ", loginSessionId=" << pbReq.sessionId();//构造响应bite_im::GetRecentMsgRsp pbResp;pbResp.setRequestId(pbReq.requestId());pbResp.setSuccess(true);pbResp.setErrmsg("");QByteArray avatar = loadFileToByteArray(":/resource/image/defaultAvatar.png");for(int i = 0; i < 20; ++i){bite_im::MessageInfo messageInfo = makeTextMessageInfo(i, "2000", avatar);pbResp.msgList().push_back(messageInfo);}//序列化QByteArray body = pbResp.serialize(&serializer);//构造http响应对象QHttpServerResponse resp(body, QHttpServerResponse::StatusCode::Ok);resp.setHeader("Content-Type", "application/x-protobuf");return resp;
}
这里我们就完成了整个加载指定会话最近消息的内容了。
相关文章:
加载指定会话最近消息
加载指定会话最近消息 前言 上一集我们就把三个标签页的加载列表的任务给完成啦!那么我们这一集就来完成加载指定绘画最近消息的任务。 需求分析 我们点击了某个会话之后,我们就会去显示我们的会话的最近的N条消息。请看下图。 我们这里涉及到两个区…...
基于tensorflow使用VGG16实现猫狗识别
import tensorflow as tf import numpy as np from tensorflow.keras import layers, models, optimizers from tensorflow.keras.preprocessing.image import ImageDataGenerator# 定义 VGG16 模型 class VGG16(tf.keras.Model):def __init__(self, num_classes2):super(VGG16…...
第18章 EXISTS 与 NOT EXISTS 关键字
一、EXISTS 关键字介绍 关键字介绍EXISTS 关联子查询通常也会和 EXISTS操作符一起来使用,用来检查在子查询中是否存在满足条件的行。 如果在子查询中当前的行不满足条件:返回 FALSE,继续在子查询中查找 如果在子查询中当前的行满足条件&…...
Windows多JDK版本管理工具JVMs
Windows多JDK版本管理工具JVMs 官网安装使用手动下载jdk 官网 https://github.com/ystyle/jvms 下载 https://github.com/ystyle/jvms/releases 当前下载版本为v2.1.6 安装 下载后,解压到某个目录。 比如:D:\soft\JVMs\jvms_v2.1.6_amd64 把这个目录…...
【C++】初始化列表、类型转换
目录: 一、const成员函数 二、初始化列表 三、类型转换 正文 一、const成员函数 (1)将const修饰的成员函数称之为const成员函数,const修饰成员函数放到成员函数参数列表的后⾯。至于为什么这么放是语法规定。 (2&a…...
创新设计,精准仿真|SOLIDWORKS Simulation 2025新功能
SOLIDWORKS Simulation 2025 带来了多项新功能,不仅提高了工作效率,还增强了仿真的精确度。以下是五大新功能的详细介绍,帮助您更好地利用这些新特性提升设计仿真能力。 1. 从分析中排除实体 在复杂的装配体仿真中,有时需要排除某…...
vue3封装Element Plus table表格组件
支持绝大部分Element Plus原有设置属性,支持分页,支持动态适配高度 效果展示 组件代码: <template><div class"table-wrap" ref"tableWrap"><el-tableclass"w100 h100":data"tableInfo.…...
Qt之QWidget相关
Qt概述 Qt 是一个跨平台的 C 开发框架。 跨平台支持:可以用于开发 Windows、macOS、Linux、Android、iOS 等多种操作系统下的应用程序。这意味着开发者使用 Qt 编写的代码,在经过适当的编译和配置后,能够在不同平台上运行,减少了…...
用web前端写出一个高校官网
所实现的效果如链接: http://127.0.0.1:5500/school.html <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>xigongshang</title> <style> * {margin: 0;padding: 0;} a{ text-decoration: none…...
【笔记】Android Gradle Plugin配置文件相关说明-libs.versions.toml
版本号 文件路径:Project\gradle\libs.versions.toml 直接搜索versions.agp是找不到的,这是变量引用的写法,查询 agp版本可以直接查版本号。 [versions] agp "8.5.0-alpha08" junit "4.13.2" junitVersion "1.…...
如何修复WordPress卡在维护模式
当你管理WordPress网站时,没有什么比看到它卡在维护模式更令人沮丧的了。特别是在你进行重要更新或期望大量流量的时候,这种情况会更加令人不安。 维护模式可能由许多因素引起,从简单的文件损坏到更复杂的插件冲突或存在的.maintenance文件。…...
glob三个函数的效果
glob 允许你给一个从dirname到basename pattern的整字符串路径,然后匹配一切符合要求的路径。 glob0 dirname和basename分开传,只返回basename。可见不支持pattern匹配。 glob1 dirname和basename pattern分开传,只返回basename。支持pa…...
FreeRTOS:事件标志组与任务通知
目录 一、事件标志组(Event Groups) 1、事件标志组的特点 2、事件标志组与队列、信号量的区别 3、关键API函数 4、示例代码 5、优缺点 6、总结 二、任务通知(Task Notifications) 1、任务通知的特点 2、关键API函数 3、…...
c++11的动态类型
c17引入了any 和 variant,可以将任意数据类型统一用any或variant类型表示,在开发中还是能够带来很多便利的。在c11版本中,可以用下面这个例子,仿照实现一个Any类型。 #include <iostream> #include <stdexcept> #inc…...
付费会员渗透难,腾讯音乐的触顶挑战
腾讯音乐付费用户增长背后,月活跃用户数下滑3%,超级会员渗透率仅1.8%。 转载|原创新熵 作者丨晓伊 编辑丨蕨影 腾讯音乐此次营收同比正增长的到来,殊为不易。要知道,此前已连续四个季度出现营收同比下滑的态势。 11月12日&#x…...
内网安全隧道搭建-ngrok-frp-nps-sapp
1.ngrok 建立内网主机与公网跳板机的连接: 内网主机为客户机: 下载客户端执行 2.frp (1)以下为内网穿透端口转发 frp服务端配置: bindPort 为frp运行端口 服务端运行 ./frps -c frps.ini frp客户端配置…...
Load-Balanced-Online-OJ(负载均衡式在线OJ)
负载均衡式在线OJ 1. 项目介绍2. 项目说明4. 项目代码5. 项目演示 1. 项目介绍 2. 项目说明 4. 项目代码 5. 项目演示...
Postman之变量操作
系列文章目录 1.Postman之安装及汉化基本使用介绍 2.Postman之变量操作 3.Postman之数据提取 4.Postman之pm.test断言操作 5.Postman之newman Postman之变量操作 1.pm.globals全局变量2.pm.environment环境变量3.pm.collectionVariables集合变量4.pm.variables5.提取数据-设置变…...
查找字符串中某个字符返回字符位置
当然有正则表达式就非常简单,没有的话也不用担心,我们自己写算法完成这个功能. 早期的vs版本不支持vs,当然也可以下载boost来实现,关键还是不想下载,那么就自己写吧. 1.要求,查找字符串中同一个字符,并找出字符的位置. 2.根据字符位置,计算出对应的x,y坐标. 算法第一步,查找字…...
《数学物理学报》
作者指南 一、目的与范围 《数学物理学报》以刊登数学与物理科学的边缘学科中具有创造性的代表学科水平的科研成果为主的综合性学术刊物。其目的旨在向专业读者(研究生水平以上)提供数理学科领域的重要的、独创的成果。 二、投稿 要求文章内容具有创新…...
CSS动画实战:5分钟搞定微信语音发送震动效果(附完整代码)
CSS动画实战:5分钟实现语音波形震动效果 最近在做一个社交类项目时,产品经理突然提出要在语音消息发送时加入波形动画效果,要求"要有微信那种专业感"。作为前端开发者,我第一反应就是:这得用Canvas吧&#x…...
告别手输!用Shell脚本自动化你的GROMACS伞形采样全流程(附赠配置文件)
告别手输!用Shell脚本自动化你的GROMACS伞形采样全流程(附赠配置文件) 在计算化学领域,GROMACS作为分子动力学模拟的利器,其强大的功能背后往往伴随着繁琐的命令行操作。特别是进行伞形采样(Umbrella Sampl…...
别再让AI瞎猜了!5个实战案例教你写出让Vibe Coding一次成功的提示词
别再让AI瞎猜了!5个实战案例教你写出让Vibe Coding一次成功的提示词 当你在Vibe Coding平台上输入一串提示词,满心期待地按下生成按钮,结果却得到一个与你想象中完全不同的产物——这种经历相信很多开发者都不陌生。为什么AI总是"误解&q…...
如何查看浏览器中当前存储的 Cookie?
如何查看浏览器中的 Cookie?为什么有些 Cookie 看不到?1. 引言:快递单号与隐私信封2. Cookie 是什么?(小白必备)3. 核心问题:为什么有些 Cookie“看不到”?4. 如何查看 Cookie&#…...
OpenCV透视变换实战:从文档矫正到AR应用
1. 透视变换基础:从原理到生活场景 想象一下你正在用手机拍摄一张放在桌上的发票,由于角度问题,发票在照片里变成了梯形。这时候你需要的正是透视变换——它能把这个梯形"掰正"成规整的矩形。在计算机视觉领域,透视变换…...
ComfyUI-WanVideoWrapper全栈指南:从认知到实践的AI视频生成解决方案
ComfyUI-WanVideoWrapper全栈指南:从认知到实践的AI视频生成解决方案 【免费下载链接】ComfyUI-WanVideoWrapper 项目地址: https://gitcode.com/GitHub_Trending/co/ComfyUI-WanVideoWrapper 一、认知篇:理解AI视频生成的技术基础 1.1 核心概念…...
别再手动写JSON Schema了!用智谱AI/DeepSeek的FunctionCall,5分钟搞定天气查询API对接
告别JSON Schema手写时代:用大模型FunctionCall极速对接天气API 开发聊天机器人时,最头疼的莫过于为每个新功能手动编写JSON Schema。上周我接手一个天气查询功能需求,原本预计要花半天时间定义参数结构、验证逻辑,结果用智谱AI的…...
告别手动重启!用宝塔PM2管理器实现Node.js热更新(2023最新配置指南)
2023终极指南:用宝塔PM2打造Node.js热更新开发流水线 每次保存代码都要手动重启服务?还在为部署中断用户体验而头疼?作为经历过数百次深夜紧急部署的全栈开发者,我总结出一套零中断热更新方案。只需15分钟配置,让你的N…...
STM32CubeMX实战:串口中断配置与数据收发全解析
1. 从零开始搭建STM32CubeMX工程 第一次接触STM32CubeMX时,我被它强大的可视化配置功能惊艳到了。这个由ST官方推出的工具,简直就是嵌入式开发者的福音。相比传统的手动编写初始化代码,CubeMX通过图形界面就能完成大部分硬件配置,…...
解锁Linux平台微信小程序开发:终极完整环境搭建指南
解锁Linux平台微信小程序开发:终极完整环境搭建指南 【免费下载链接】wechat-web-devtools-linux 适用于微信小程序的微信开发者工具 Linux移植版 项目地址: https://gitcode.com/gh_mirrors/we/wechat-web-devtools-linux 你是否曾为在Linux系统上无法使用微…...
