数据中心类DataCenter(一)
数据中心类DataCenter(一)
前言
上一集我们就完成了整个核心数据类型从proto到cpp代码的转换。我们这一集就开始完成数据中心类DataCenter。
设置单例模式
我们每一个客户端都应该对应着一个数据中心与服务端进行对接,我们这里需要给这个数据中心类设置为单例模式,不能让外界调用这个类的构造函数。
代码添加以下内容即可
public:static DataCenter* getInstance();
private:DataCenter();static DataCenter* instance;
namespace model{DataCenter* DataCenter::instance = nullptr;DataCenter *DataCenter::getInstance()
{if(instance == nullptr){instance = new DataCenter();}return instance;
}DataCenter::DataCenter()
{}
需要管理什么数据?
当前客户端登录到服务器对应的登录id
LoginSession是服务器开发中的一个典型的实现登录的方式。
这里我们就详细的谈谈
在网络通信中,HTTP协议是一种“无状态”协议,这意味着每次HTTP请求和响应之间是相互独立的,服务器不会自动保存任何关于客户端状态的信息。然而,在实际的业务场景中,我们经常需要在客户端和服务器之间维持一种“有状态”的交互,以提供更加连贯和个性化的服务体验。
以客户端用户1为例,当它首次通过用户名和密码成功登录服务器后,我们希望在后续的交互中不再重复验证其身份,而是能够无缝地继续通信。这时,登录会话机制就显得尤为重要。
登录会话机制的工作原理是这样的:一旦客户端用户1成功登录,服务器就会在内存中为该客户端创建一个会话,并保存必要的用户信息。同时,服务器会生成一个唯一的登录会话ID,这个ID相当于客户端的“电子通行证”。服务器将这个会话ID返回给客户端,客户端在之后的每次请求中只需携带这个会话ID,而无需重复发送用户名和密码。
通过这种方式,服务器可以识别出携带会话ID的客户端用户1,并验证其身份的合法性。这样,客户端用户1就能够在无需重复身份验证的情况下,与服务器进行多次交互,大大提升了用户体验和系统的效率。
简而言之,登录会话机制为无状态的HTTP协议提供了一种状态管理的手段,使得客户端能够在保持身份验证的同时,与服务器进行连续的、有状态的交互。这种机制不仅提高了安全性,还优化了性能,是现代网络应用中不可或缺的一部分。
当前用户信息
登录进入主窗口之后,我们就是需要访问主窗口的很多内容,我们就通过主窗口的内容来继续完成我们数据中心类需要管理的数据。
请看下图
可以看到我们的左上角有一个图片,我们看过前面博客的同学都知道我们点击这个头像之后就可以访问我们自己的用户信息。那么我们的数据中心就需要保存我们的用户信息。
会话列表
我们看到我们头像下面的三大标签页,这分别代表了会话列表、好友列表以及好友申请列表。
那么我们就需要保存这三个列表。
会话列表就是一个QList,里面装的就是一堆ChatSessionInfo的对象。
好友列表
有了会话列表,我们一样要有好友列表,也是通过QList进行保存每一个用户的UserInfo即可。
好友申请列表
这个列表用于存储未处理的申请好友的用户信息。
记录当前选中的会话
我们看到中间,我们有n个会话,那么我们点击了某个会话,我们就应该记录一下这个会话的id即可。
记录每个会话的所有成员
这个主要针对我们的群聊的会话,那么我们每个会话应该都应该有n个成员,那么我们就要把这些成员用一个QList来存放,那么QList里面存放的就是我们的UserInfo即可,那么还不够,我们要知道是哪个会话才行,所以我们就要记录会话的id,那么怎么才能让他们两个联系起来,那就是用QHash连接起来即可,我们的key就是chatSessionId,value就是UserInfo的列表。
记录每个会话的最近消息列表
我们消息编辑区的历史记录也得完成一下功能啊,所以我们也要记录一下每个会话的最近消息列表。也是用QHush即可,key为我们的会话id,value为我们的消息列表。
记录每个会话未读消息条数
key就是我们的会话id,value就是一个int的值,用于记录条数!
好友搜索结果
我们需要返回的是一个UserInfo的一个列表
历史消息记录搜索结果
这个也是搜索之后得到的结果!
返回的是Message的列表
我们要先找到这个按钮
之后进入里面,搜索的结果就是下图
短信验证码验证id
这个是很关键的内容。
服务器端操作:
当用户请求发送短信验证码时,服务器会执行以下步骤:
- 生成验证码:服务器生成一个随机字符串作为
verifyCodeId
(例如“aabbccdd”),并生成另一个数字作为verifyCode
(验证码),这里显示为“112233”。 - 保存验证码信息:服务器将这两个信息以键值对的形式保存起来,即
aabbccdd: 112233
,以便后续验证时使用。 - 调用第三方SDK发送短信:服务器调用第三方短信服务SDK(如阿里云短信服务),通过网络请求告诉第三方服务给指定的手机号码发送验证码。
短信发送:
第三方短信服务接收到请求后,会向用户的手机发送包含验证码的短信。
客户端保存verifyCodeId
:
用户的手机收到验证码后,客户端(可能是一个应用程序或网页)需要保存当前的verifyCodeId
,以备后续发送校验请求时进行验证。
避免干扰:
由于可能在同一时刻有很多客户端发起短信验证请求,服务器需要确保这些请求不会相互干扰。这通常通过确保每个请求的verifyCodeId
是唯一的来实现。
用户输入验证码:
用户收到短信验证码后,需要在客户端输入这个验证码,以及之前保存的verifyCodeId
,然后提交给服务器进行验证。
服务器验证:
服务器接收到客户端的验证请求后,会根据提交的verifyCodeId
查找对应的verifyCode
,并验证用户输入的验证码是否正确。
验证结果:
如果验证码正确,服务器会返回验证成功的响应,允许用户继续后续操作。
如果验证码错误或过期,服务器会返回验证失败的响应,并可能要求用户重新发送验证码。
这个流程确保了用户身份的验证,同时也提供了一种安全的方式来防止未授权的访问。通过短信验证码,即使攻击者知道了用户的其他信息,没有手机验证码也无法通过验证,从而增强了账户的安全性。
总代码
#ifndef DATACENTER_H
#define DATACENTER_H#include "data.h"#include <QWidget>namespace model{
class DataCenter : public QObject
{Q_OBJECTpublic:static DataCenter* getInstance();
private:DataCenter();static DataCenter* instance;//列出DataCenter中要组织管理的所有的数据//当前客户端登录到服务器对应的登录会话idQString loginSessionId;//当前的用户信息UserInfo* myself = nullptr;//好友列表QList<UserInfo>* friendList = nullptr;//会话列表QList<ChatSessionInfo>* chatSessionList = nullptr;//记录当前选中的会话QString currentChatSessionId = "";//记录每个会话中都有哪些成员/*** key: chatSessionId* value: UserInfo列表*/QHash<QString, QList<UserInfo>>* memberList = nullptr;//待处理的好友申请列表QList<UserInfo>* applyList = nullptr;//每个会话的最近消息列表/*** key: chatSessionId* value: Message列表*/QHash<QString, QList<Message>>* recentMessage = nullptr;//存储每个会话,未读消息的个数/*** key: chatSessionId* value: 未读消息个数*/QHash<QString, int>* unreadMessageCount = nullptr;//用户的好友搜索结果QList<UserInfo>* searchUserResult = nullptr;//历史消息搜索结果QList<Message>* searchMessageResult = nullptr;//短信验证码的验证 idQString currentVerifyCodeId = "";signals:
};
} //end namespace
#endif // DATACENTER_H
这就是我们DataCenter需要保存的内容!
为什么需要这样一个数据中心类
集中式数据管理
DataCenter 类集中管理了所有与用户相关的数据,包括用户信息、好友列表、会话列表、消息列表等。这种集中式管理有助于减少代码中的重复数据管理逻辑,使得数据的维护和更新更加方便。
解耦合
DataCenter 类作为数据管理的中间层,可以减少业务逻辑代码与数据存储之间的耦合。业务逻辑代码只需要与DataCenter 交互,而不需要关心数据是如何存储和检索的。
单例模式的应用
DataCenter 类使用了单例模式,确保了全局只有一个数据管理实例。这有助于避免多个实例之间的数据不一致问题,并且可以减少资源消耗。
那么这一集我们就先到这里!!!