- 软件设计及核心代码展示
- 数据库表设计,ES搜索表设计,Redis键值对设计
- 数据库表设计
(1)用户表设计
这里的ID是指的是在系统中用户是第几个注册的(从1开始)
user_id是指用户的唯一ID是通过uuid()函数生成的一串数字(会与第一个ID有点冗余)
Nickname是用户的昵称
Description是用户的一个简介
Password是用户的密码
Phone是用户的电话号码
avatar_id是用户的头像ID(会通过这个ID找到对应在服务端的文件头像)
这张表对对应的C++类如下
private:
friend class odb::access;
#pragma db id auto
unsigned long _id;
#pragma db type("varchar(64)") index unique
std::string _user_id;
#pragma db type("varchar(64)") index unique
odb::nullable<std::string> _nickname; //用户昵称-不一定存在
odb::nullable<std::string> _description; //用户签名 - 不一定存在
#pragma db type("varchar(64)")
odb::nullable<std::string> _password; //用户密码 - 不一定存在
#pragma db type("varchar(64)") index unique
odb::nullable<std::string> _phone; //用户手机号 - 不一定存在
#pragma db type("varchar(64)")
odb::nullable<std::string> _avatar_id; //用户头像文件ID - 不一定存在
- 聊天会话表
ID是指每个会话在数据库中的创建次序(从1开始)
chat_session_id是指这个会话通过uuid()函数生成的唯一字符串
chat_session_name是指会话名字
chat_session_id是指会话的类型(群聊会话还是单聊会话)
它所对应的C++类
private:
friend class odb::access;
#pragma db id auto
unsigned long _id;
#pragma db type("varchar(64)") index unique
std::string _chat_session_id;
#pragma db type("varchar(64)")
std::string _chat_session_name;
#pragma db type("tinyint")
ChatSessionType _chat_session_type; //1-单聊; 2-群聊
- 聊天会话成员表
ID和前面的一样
session_id每个会话的ID,和上一张表的回话ID对应
user_id用户ID
所对应的C++类
private:
friend class odb::access;
#pragma db id auto
unsigned long _id;
#pragma db type("varchar(64)") index
std::string _session_id;
#pragma db type("varchar(64)")
std::string _user_id;
- 聊天消息表
message_id是消息的一个唯一ID,通过uuid()生成
Session_id是消息所属于那个的回话的ID
user_id是消息发送者的ID
message_type是指消息的类型(文字消息,图片消息,文件消息,语音消息)
create_time消息创建时间
Content信息内容(只有文字消息才有)
file_id文件ID(只有图片,文件,语音消息才有)
file_name文件名字(只有图片,文件,语音消息才有)
file_size文件大小(只有图片,文件,语音消息才有)
对应的C++类
private:
friend class odb::access;
#pragma db id auto
unsigned long _id;
#pragma db type("varchar(64)") index unique
std::string _message_id;
#pragma db type("varchar(64)") index
std::string _session_id; //所属会话ID
#pragma db type("varchar(64)")
std::string _user_id; //发送者用户ID
unsigned char _message_type; //消息类型 0-文本;1-图片;2-文件;3-语音
#pragma db type("TIMESTAMP")
boost::posix_time::ptime _create_time; //消息的产生时间
odb::nullable<std::string> _content; //文本消息内容--非文本消息可以忽略
#pragma db type("varchar(64)")
odb::nullable<std::string> _file_id; //文件消息的文件ID -- 文本消息忽略
#pragma db type("varchar(128)")
odb::nullable<std::string> _file_name; //文件消息的文件名称 -- 只针对文件消息有效
odb::nullable<unsigned int> _file_size; //文件消息的文件大小 -- 只针对文件消息有效
- 关系表
User_id用户的ID
peer_id用户ID对应的好友的ID(表是双向存在的,有用户添加成功时,要同时添加两条数据)
private:
friend class odb::access;
#pragma db id auto
unsigned long _id;
#pragma db type("varchar(64)") index
std::string _user_id;
#pragma db type("varchar(64)")
std::string _peer_id;
- 好友申请表
user_id发起请求的用户ID;
peer_id接收请求的用户ID
Event_id本次事件的ID(当事件被peer_id处理以后,无论是同意或者拒绝,事件都会被删除)
private:
friend class odb::access;
#pragma db id auto
unsigned long _id;
#pragma db type("varchar(64)") index
std::string _user_id;
#pragma db type("varchar(64)") index
std::string _peer_id;
#pragma db type("varchar(64)") index unique
std::string _event_id;
- ES搜索表设计
因为用户主要是搜索其他用户和历史消息,所以ES搜索引擎中只存储了这两类搜索
{
"mappings": {
"properties": {
"user_id": {
"type": "keyword",
"fields": {
"standard": {
"type": "text",
"analyzer": "standard"
}
}
},
"nickname": {
"type": "text"
},
"phone": {
"type": "keyword",
"fields": {
"standard": {
"type": "text",
"analyzer": "standard"
}
}
},
"description": {
"type": "text",
"analyzer": "standard"
},
"avatar_id": {
"type": "keyword",
"fields": {
"standard": {
"type": "text",
"analyzer": "standard"
}
}
}
}
}
}
上面是创建user信息的ES索引json映射,内容含有和数据库里面的user表一样
{
"mappings": {
"properties": {
"user_id": {
"type": "keyword",
"fields": {
"standard": {
"type": "text",
"analyzer": "standard"
}
}
},
"message_id": {
"type": "keyword",
"fields": {
"standard": {
"type": "text",
"analyzer": "standard"
}
}
},
"create_time": {
"type": "long"
},
"chat_session_id": {
"type": "keyword",
"fields": {
"standard": {
"type": "text",
"analyzer": "standard"
}
}
},
"content": {
"type": "text"
}
}
}
}
上面是创建message信息的ES索引json映射,内容含有和数据库里面的message表一样
- Redis键值对设计
这是session键值对的设计,主要记录了当一个用户登录时,系统会为他分配一个会话ID
class Session {
public:
using ptr = std::shared_ptr<Session>;
Session(const std::shared_ptr<sw::redis::Redis> &redis_client):
_redis_client(redis_client){}
void append(const std::string &ssid, const std::string &uid) {
_redis_client->set(ssid, uid);
}
void remove(const std::string &ssid) {
_redis_client->del(ssid);
}
sw::redis::OptionalString uid(const std::string &ssid) {
return _redis_client->get(ssid);
}
private:
std::shared_ptr<sw::redis::Redis> _redis_client;
};
这是状态键值对的设计,主要是和会话键值对配合使用,当用户登录时,状态键值对会将用户添加,表示用户已经登录,当其他地方有同一个用户登录时就会查询到并拒绝
class Status {
public:
using ptr = std::shared_ptr<Status>;
Status(const std::shared_ptr<sw::redis::Redis> &redis_client):
_redis_client(redis_client){}
void append(const std::string &uid) {
_redis_client->set(uid, "");
}
void remove(const std::string &uid) {
_redis_client->del(uid);
}
bool exists(const std::string &uid) {
auto res = _redis_client->get(uid);
if (res) return true;
return false;
}
private:
std::shared_ptr<sw::redis::Redis> _redis_client;
};
这是验证码键值对,当用户请求发送验证码时,验证码就会记录在这里一份,拿出来和用户发的验证码进行比较,一定时间后会自动删除
class Codes {
public:
using ptr = std::shared_ptr<Codes>;
Codes(const std::shared_ptr<sw::redis::Redis> &redis_client):
_redis_client(redis_client){}
void append(const std::string &cid, const std::string &code,
const std::chrono::milliseconds &t = std::chrono::milliseconds(300000)) {
_redis_client->set(cid, code, t);
}
void remove(const std::string &cid) {
_redis_client->del(cid);
}
sw::redis::OptionalString code(const std::string &cid) {
return _redis_client->get(cid);
}
private:
std::shared_ptr<sw::redis::Redis> _redis_client;
};