用户登录业务代码和测试

72 阅读2分钟

1. 完善include/public.hpp

#ifndef PUBLIC_H
#define PUBLIC_H

// server和client的公共文件
enum EnMsgType
{
    LOGIN_MSG = 1, //登录消息
    LOGIN_MSG_ACK, //登录响应消息
    REG_MSG,       //注册消息
    REG_MSG_ACK    //注册响应消息
};

#endif

2. 完善include/server/model/usermodel.hpp

#ifndef USERMODEL_H
#define USERMODEL_H

#include "user.hpp"

// User表的数据操作类,和业务不相关,针对表的CRUD
class UserModel
{
public:
    // User表的增加方法
    bool insert(User &user);

    //根据用户号码查询用户信息
    User query(int id);

    //更新用户的状态信息
    bool updateState(User user);
};

#endif

3. 完善include/server/model/usermodel.cpp,这个文件负责连接数据库进行的DRUD

#include "usermodel.hpp"
#include "db.h"

#include <iostream>
using namespace std;

bool UserModel::insert(User &user)
{
    // 1. 组装sql语句
    char sql[1024] = {0};
    // 此处刚注册,还没有登录,肯定是offline,我们在User类的构造函数里state默认为offline
    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;

    if (mysql.connect()) // 2. 连接数据库
    {
        if (mysql.update(sql)) // 3. 发送sql语句插入数据
        {
            //获取插入成功的用户数据生成的主键id
            user.setId(mysql_insert_id(mysql.getConnection()));
            return true;
        }
    }
    return false;
}
User UserModel::query(int id)
{
    // 1. 组装sql语句
    char sql[1024] = {0};
    // 此处刚注册,还没有登录,肯定是offline,我们在User类的构造函数里state默认为offline
    sprintf(sql, "select * from user where id = %d", id);
    MySQL mysql;

    if (mysql.connect()) // 2. 连接数据库
    {
        // malloc申请了资源,需要释放
        MYSQL_RES *res = mysql.query(sql);
        if (res != nullptr)
        {
            MYSQL_ROW row = mysql_fetch_row(res);
            if (row != nullptr)
            {
                User user;
                user.setId(atoi(row[0]));
                user.setName(row[1]);
                user.setPwd(row[2]);
                user.setState(row[3]);
                // 释放结果集占用的资源
                mysql_free_result(res);
                return user;
            }
        }
    }
    // 如果数据库没有连接上,或者没查找到id对应数据,则返回默认构造的user,id=-1
    return User();
}
//更新用户的状态信息
bool UserModel::updateState(User user)
{
    // 1. 组装sql语句
    char sql[1024] = {0};
    sprintf(sql, "update user set state = '%s' where id = %d", user.getState().c_str(), user.getId());
    MySQL mysql;

    if (mysql.connect()) // 2. 连接数据库
    {
        if (mysql.update(sql))
        {
            return true;
        }
    }
    return false;
}

4. 完善src/server/chatservice.cpp中的login方法

#include "chatservice.hpp"
#include "public.hpp"

#include <muduo/base/Logging.h>
#include <string>
using namespace std;
using namespace muduo;

//获取单例对象的接口函数
ChatService *ChatService::instance()
{
    static ChatService service;
    return &service;
}

//注册消息以及对应的回调操作
ChatService ::ChatService()
{
    _msgHandlerMap.insert({LOGIN_MSG, bind(&ChatService::login, this, _1, _2, _3)});
    _msgHandlerMap.insert({REG_MSG, bind(&ChatService::reg, this, _1, _2, _3)});
}

//获取消息对应的处理器
MsgHandler ChatService::getHandler(int msgid)
{
    //记录错误日志,msgid没有对应的事件处理回调
    auto it = _msgHandlerMap.find(msgid);
    if (it == _msgHandlerMap.end())
    {
        //返回一个默认的处理器,空操作
        return [=](const TcpConnectionPtr &conn, json &js, Timestamp)
        {
            LOG_ERROR << "msgid:" << msgid << " can not find handler!";
        };
    }
    else
    {
        return _msgHandlerMap[msgid];
    }
}

//处理登录业务
void ChatService ::login(const TcpConnectionPtr &conn, json &js, Timestamp)
{
    int id = js["id"];
    string pwd = js["password"];

    User user = _userModel.query(id);
    if (user.getId() == id && user.getPwd() == pwd)
    {
        //该用户已经登录,不允许重复登录
        if (user.getState() == "online")
        {
            json responce;
            responce["msgid"] = LOGIN_MSG_ACK;
            responce["errno"] = 2;
            responce["errmsg"] = "该账号已经登录,请重新输入账号";
            conn->send(responce.dump());
        }
        //登陆成功,更新用户状态信息state offline->online
        else
        {
            user.setState("online");
            _userModel.updateState(user);

            json responce;
            responce["msgid"] = LOGIN_MSG_ACK;
            responce["errno"] = 0;
            responce["id"] = user.getId();
            responce["name"] = user.getName();
            conn->send(responce.dump());
        }
    }
    else
    {
        //该用户不存在或者用户存在但是密码错误,登陆失败
        json responce;
        responce["msgid"] = LOGIN_MSG_ACK;
        responce["errno"] = 1;
        responce["errmsg"] = "用户名或密码错误";
        conn->send(responce.dump());
    }
}
//处理注册业务
void ChatService ::reg(const TcpConnectionPtr &conn, json &js, Timestamp)
{
    string name = js["name"];
    string pwd = js["password"];

    User user;
    user.setName(name);
    user.setPwd(pwd);
    bool state = _userModel.insert(user);

    if (state)
    {
        //注册成功
        json responce;
        responce["msgid"] = REG_MSG_ACK;
        // errno=0响应成功,不为0那肯定还有errmsg说明错误消息
        responce["errno"] = 0;
        responce["id"] = user.getId();
        conn->send(responce.dump());
    }
    else
    {
        //注册失败
        json responce;
        responce["msgid"] = REG_MSG_ACK;
        responce["errno"] = 1;
        conn->send(responce.dump());
    }
}

5. 编译测试

image.png