在前几节的研究中,我们已经实现网络层与业务层分离,本节实现数据层与业务层分离,降低各层之间的耦合性,同时实现用户注册业务。
网络层专注于处理网络通信与读写事件
业务层专注于处理读写事件到来时所需求的各项业务
数据层专注于与底层数据库间进行增删改查。
数据库中有User、Friend、AllGroup、GroupUser和OfflineMessage表,在model数据层中,要提供一些类与数据库中的表对应起来,以便于将数据库中读取到的字段信息也对象的方式提供给业务模块使用
项目流程如下:
1、项目环境搭建
C++项目——集群聊天服务器项目(一)项目介绍、环境搭建、Boost库安装、Muduo库安装、Linux与vscode配置_c++集群聊天服务器-CSDN博客
2、Json第三方库介绍
C++项目——集群聊天服务器项目(二)Json第三方库-CSDN博客
3、muduo网络库介绍
C++项目——集群聊天服务器项目(三)muduo网络库-CSDN博客
4、MySQL数据库创建
C++项目——集群聊天服务器项目(四)MySQL数据库-CSDN博客
5、网络模块与业务模块代码编写
C++项目——集群聊天服务器项目(五)网络模块与业务模块-CSDN博客
6、MySQL模块编写
C++项目——集群聊天服务器项目(六)MySQL模块-CSDN博客
一、User类
在include/server下创建model文件夹,在model文件夹下创建与用户表对应的、操作用户的User类,定义在头文件user.hpp中,由于代码体量较小,直接在头文件中进行实现
用户表user
#ifndef USER_H
#define USER_H
#include <string>
using namespace std;
//User表的ORM类
class User
{
public:
User(int id = -1, string name = "", string pwd = "", string state = "offline")
{
this->id = id;
this->name = name;
this->password = pwd;
this->state = state;
}
//设置
void setId(int id) { this->id = id; }
void setName(string name) { this->name = name; }
void setPwd(string pwd) { this->password = pwd; }
void setState(string state) { this->state = state; }
//获取
int getId() { return this->id; }
string getName() { return this->name; }
string getPwd() { return this->password; }
string getState() { return this->state; }
protected:
int id;//ID号
string name;//姓名
string password;//密码
string state;//状态
};
#endif
二、UserModel类
UserModel为操纵数据库User表的类,主要实现增加用户、查询用户、更新用户、重置用户信息
在include/server/model文件创建usermodel.hpp
#ifndef USERMODEL_H
#define USERMODEL_H
#include "user.hpp"
//User表的数据操作类
class UserModel {
public:
//User表的增加方法
bool insert(User &user);
//根据用户号码查询用户信息
User query(int id);
//更新用户的状态信息
bool updateState(User user);
//重置用户的状态信息
void resetState();
};
#endif
在src/server中创建model文件夹,创建usermodel.cpp对UserModel类中insert方法进行实现
#include "usermodel.hpp"
#include "db.hpp"
#include <iostream>
using namespace std;
// User表的增加方法
bool UserModel::insert(User &user)
{
// 1.组装sql语句
char sql[1024] = {0};
sprintf(sql, "insert into user(name, password, state) values('%s', '%s', '%s')",
user.getName().c_str(), user.getPwd().c_str(), user.getState().c_str());
MySQL mysql; // 定义一个mysql对象
if (mysql.connect()) // 连接成功了
{
if (mysql.update(sql)) // 更新这个sql语句传进去
{
// 获取插入成功的用户数据生成的主键id
user.setId(mysql_insert_id(mysql.getConnection())); // 拿到数据库生成的id作为用户的id号
return true;
}
}
return false;
}
其余方法在实现后续功能模块中进行实现
三、注册功能
本节来实现注册功能,判断是否能通过UserModel类顺利将用户信息插入数据库中。
在public.hpp中定义注册消息和注册响应消息
#ifndef PUBLIC_H
#define PUBLIC_H
/*
server和client的公共文件
*/
enum EnMsgType
{
LOGIN_MSG = 1, //登录消息
REG_MSG, //注册消息
REG_MSG_ACK, //注册响应消息
};
#endif
注:此时登录消息对应的msgid=1,注册消息对应的msgid=2
在第五节C++项目——集群聊天服务器项目(五)网络模块与业务模块-CSDN博客中,注册与登录信息仅仅为一个日志信息,此处将注册业务进行实现
在chatservice.hpp中,定义用户操作类对象
#ifndef CHATSERVICE_H
#define CHATSERVICE_H
#include <muduo/net/TcpConnection.h>
#include <unordered_map>//一个消息ID映射一个事件处理
#include <functional>
using namespace std;
using namespace muduo;
using namespace muduo::net;
#include "usermodel.hpp"
#include "json.hpp"
using json = nlohmann::json;
//表示处理消息的事件回调方法类型,事件处理器,派发3个东西
using MsgHandler = std::function<void(const TcpConnectionPtr &conn, json &js, Timestamp)>;
//聊天服务器业务类
class ChatService
{
public:
//获取单例对象的接口函数
static ChatService *instance();
//处理登录业务
void login(const TcpConnectionPtr &conn, json &js, Timestamp time);
//处理注册业务
void reg(const TcpConnectionPtr &conn, json &js, Timestamp time);
private:
ChatService();//单例
//存储消息id和其对应的业务处理方法,消息处理器的一个表,写消息id对应的处理操作
unordered_map<int, MsgHandler> _msgHandlerMap;
//数据操作类对象
UserModel _userModel;
};
#endif
在chatservice.cpp中,编写注册业务函数
// 处理注册业务 name password
void ChatService::reg(const TcpConnectionPtr &conn, json &js, Timestamp time)
{
string name = js["name"]; // 获取名字
string pwd = js["password"]; // 获取密码
User user; // 创建用户对象
user.setName(name);
user.setPwd(pwd);
bool state = _userModel.insert(user); // 新用户的插入
if (state) // 插入成功
{
// 注册成功
json response;
response["msgid"] = REG_MSG_ACK;
response["errno"] = 0;
response["id"] = user.getId();
conn->send(response.dump()); // 回调 ,返回json字符串
}
else // 插入失败
{
// 注册失败
json response;
response["msgid"] = REG_MSG_ACK;
response["errno"] = 1;
conn->send(response.dump()); // 回调 ,返回json字符串
}
}
步骤:
(1)从json对象中获取姓名和密码
(2)实例化User对象,分别将姓名和密码传入,使用UserModel类进行新用户的插入
注:状态默认为不在线(实际上创建的时候用户确实不在线),id由数据库派发
(3)定义json对象,回调响应信息,error = 0代表创建成功,error = 1代表创建失败。
若创建成功,需额外将创建成功的用户id号返回,如果失败,直接将json序列化发送回客户端
四、功能实现
使用CMake编译成功后,执行我们的ChatServer服务器,开启监听客户端连接
客户端使用下述命令登录服务器
telnet 127.0.0.1 6000
密码:123456
服务端显示有一个新的连接接入
客户端输入
{"msgid":2,"name":"Jiao","password":"123456"}
创建成功,返回error=0,用户id号以及注册响应msgid,如图所示
客户端,显示mysql连接成功了
我们进底层数据库看一下,
新建用户成功,功能实现完毕!(其他用户为自行学习时创建的)
感兴趣的小伙伴一起来试一下吧~
如果有问题还请及时联系我哦,感谢~