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

加载指定会话最近消息

加载指定会话最近消息

前言

上一集我们就把三个标签页的加载列表的任务给完成啦!那么我们这一集就来完成加载指定绘画最近消息的任务。

需求分析

我们点击了某个会话之后,我们就会去显示我们的会话的最近的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;
}

这里我们就完成了整个加载指定会话最近消息的内容了。

相关文章:

加载指定会话最近消息

加载指定会话最近消息 前言 上一集我们就把三个标签页的加载列表的任务给完成啦&#xff01;那么我们这一集就来完成加载指定绘画最近消息的任务。 需求分析 我们点击了某个会话之后&#xff0c;我们就会去显示我们的会话的最近的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操作符一起来使用&#xff0c;用来检查在子查询中是否存在满足条件的行。 如果在子查询中当前的行不满足条件&#xff1a;返回 FALSE&#xff0c;继续在子查询中查找 如果在子查询中当前的行满足条件&…...

Windows多JDK版本管理工具JVMs

Windows多JDK版本管理工具JVMs 官网安装使用手动下载jdk 官网 https://github.com/ystyle/jvms 下载 https://github.com/ystyle/jvms/releases 当前下载版本为v2.1.6 安装 下载后&#xff0c;解压到某个目录。 比如&#xff1a;D:\soft\JVMs\jvms_v2.1.6_amd64 把这个目录…...

【C++】初始化列表、类型转换

目录&#xff1a; 一、const成员函数 二、初始化列表 三、类型转换 正文 一、const成员函数 &#xff08;1&#xff09;将const修饰的成员函数称之为const成员函数&#xff0c;const修饰成员函数放到成员函数参数列表的后⾯。至于为什么这么放是语法规定。 &#xff08;2&a…...

创新设计,精准仿真|SOLIDWORKS Simulation 2025新功能

SOLIDWORKS Simulation 2025 带来了多项新功能&#xff0c;不仅提高了工作效率&#xff0c;还增强了仿真的精确度。以下是五大新功能的详细介绍&#xff0c;帮助您更好地利用这些新特性提升设计仿真能力。 1. 从分析中排除实体 在复杂的装配体仿真中&#xff0c;有时需要排除某…...

vue3封装Element Plus table表格组件

支持绝大部分Element Plus原有设置属性&#xff0c;支持分页&#xff0c;支持动态适配高度 效果展示 组件代码&#xff1a; <template><div class"table-wrap" ref"tableWrap"><el-tableclass"w100 h100":data"tableInfo.…...

Qt之QWidget相关

Qt概述 Qt 是一个跨平台的 C 开发框架。 跨平台支持&#xff1a;可以用于开发 Windows、macOS、Linux、Android、iOS 等多种操作系统下的应用程序。这意味着开发者使用 Qt 编写的代码&#xff0c;在经过适当的编译和配置后&#xff0c;能够在不同平台上运行&#xff0c;减少了…...

用web前端写出一个高校官网

所实现的效果如链接&#xff1a; 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

版本号 文件路径&#xff1a;Project\gradle\libs.versions.toml 直接搜索versions.agp是找不到的&#xff0c;这是变量引用的写法&#xff0c;查询 agp版本可以直接查版本号。 [versions] agp "8.5.0-alpha08" junit "4.13.2" junitVersion "1.…...

如何修复WordPress卡在维护模式

当你管理WordPress网站时&#xff0c;没有什么比看到它卡在维护模式更令人沮丧的了。特别是在你进行重要更新或期望大量流量的时候&#xff0c;这种情况会更加令人不安。 维护模式可能由许多因素引起&#xff0c;从简单的文件损坏到更复杂的插件冲突或存在的.maintenance文件。…...

glob三个函数的效果

glob 允许你给一个从dirname到basename pattern的整字符串路径&#xff0c;然后匹配一切符合要求的路径。 glob0 dirname和basename分开传&#xff0c;只返回basename。可见不支持pattern匹配。 glob1 dirname和basename pattern分开传&#xff0c;只返回basename。支持pa…...

FreeRTOS:事件标志组与任务通知

目录 一、事件标志组&#xff08;Event Groups&#xff09; 1、事件标志组的特点 2、事件标志组与队列、信号量的区别 3、关键API函数 4、示例代码 5、优缺点 6、总结 二、任务通知&#xff08;Task Notifications&#xff09; 1、任务通知的特点 2、关键API函数 3、…...

c++11的动态类型

c17引入了any 和 variant&#xff0c;可以将任意数据类型统一用any或variant类型表示&#xff0c;在开发中还是能够带来很多便利的。在c11版本中&#xff0c;可以用下面这个例子&#xff0c;仿照实现一个Any类型。 #include <iostream> #include <stdexcept> #inc…...

付费会员渗透难,腾讯音乐的触顶挑战

腾讯音乐付费用户增长背后&#xff0c;月活跃用户数下滑3%&#xff0c;超级会员渗透率仅1.8%。 转载|原创新熵 作者丨晓伊 编辑丨蕨影 腾讯音乐此次营收同比正增长的到来&#xff0c;殊为不易。要知道&#xff0c;此前已连续四个季度出现营收同比下滑的态势。 11月12日&#x…...

内网安全隧道搭建-ngrok-frp-nps-sapp

1.ngrok 建立内网主机与公网跳板机的连接&#xff1a; 内网主机为客户机&#xff1a; 下载客户端执行 2.frp &#xff08;1&#xff09;以下为内网穿透端口转发 frp服务端配置&#xff1a; bindPort 为frp运行端口 服务端运行 ./frps -c frps.ini frp客户端配置&#xf…...

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坐标. 算法第一步,查找字…...

《数学物理学报》

作者指南 一、目的与范围 《数学物理学报》以刊登数学与物理科学的边缘学科中具有创造性的代表学科水平的科研成果为主的综合性学术刊物。其目的旨在向专业读者&#xff08;研究生水平以上&#xff09;提供数理学科领域的重要的、独创的成果。 二、投稿 要求文章内容具有创新…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

python执行测试用例,allure报乱码且未成功生成报告

allure执行测试用例时显示乱码&#xff1a;‘allure’ &#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;ڲ&#xfffd;&#xfffd;&#xfffd;&#xfffd;ⲿ&#xfffd;&#xfffd;&#xfffd;Ҳ&#xfffd;&#xfffd;&#xfffd;ǿ&#xfffd;&am…...

使用 SymPy 进行向量和矩阵的高级操作

在科学计算和工程领域&#xff0c;向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能&#xff0c;能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作&#xff0c;并通过具体…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

Redis:现代应用开发的高效内存数据存储利器

一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发&#xff0c;其初衷是为了满足他自己的一个项目需求&#xff0c;即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源&#xff0c;Redis凭借其简单易用、…...

C++ 设计模式 《小明的奶茶加料风波》

&#x1f468;‍&#x1f393; 模式名称&#xff1a;装饰器模式&#xff08;Decorator Pattern&#xff09; &#x1f466; 小明最近上线了校园奶茶配送功能&#xff0c;业务火爆&#xff0c;大家都在加料&#xff1a; 有的同学要加波霸 &#x1f7e4;&#xff0c;有的要加椰果…...