(六)用户登录模块讲解

登录验证

json对象中获取用户ID和密码,并在数据库中查询获取用户信息。

int id = js["id"].get<int>();
std::string password = js["password"];

如果用户已经登录过,即state == "online",则返回错误信息。

if (user.getId() == id && user.getPassword() == password)
{
	if (user.getState() == "online")
	{
		// 该用户已经登录,不能重复登录
		json response;
		response["msgid"] = LOGIN_MSG_ACK;
		response["errno"] = 2;
		response["errmsg"] = "this account is using, input another!";
		conn->send(response.dump());
	}
	else
	{
		// ...
	}
}

登录成功后,需要在用户表_userConnMap<ID, TcpConnection>中记录新登录的用户。考虑到多线程对此map进行操作,我们需要使用互斥锁。

// 登录成功,记录用户连接信息
// 需要考虑线程安全问题 onMessage会在不同线程中被调用
{
	lock_guard<mutex> lock(_connMutex);
	_userConnMap.insert({id, conn});
}

lock_guard遵守RALL手法,初始化即上锁,销毁即解锁。这里用临时作用域让锁得颗粒度变小,保证性能。

查询离线消息

我们还需要查询该用户离线时是否有离线消息,如果有离线消息是要取出放到vector<string>容器中得。我们可以使用 JSON 直接与 STL 容器进行操作。

// 查询该用户是否有离线消息
std::vector<std::string> vec = _offlineMsgModel.query(id);
if (!vec.empty())
{
	response["offlinemsg"] = vec;
	// 读取该用户的离线消息后,将该用户离线消息删除掉
	_offlineMsgModel.remove(id);
}

显示好友列表

我们还需要显示这个登录用户得好友列表,在 MySQL 中记录着每个用户 ID 的好友名单。我们需要取出来,并且加入到 JSON 对象中。

std::vector<User> userVec = _friendModel.query(id);
if (!userVec.empty())
{
	std::vector<std::string> vec;
	for (auto& user : userVec)
	{
		json js;
		js["id"] = user.getId();
		js["name"] = user.getName();
		js["state"] = user.getState();
		vec.push_back(js.dump());
	}
	response["friends"] = vec;
}

conn->send(response.dump());

登录模块完整代码

#include "chatservice.hpp"
#include "public.hpp"
#include <muduo/base/Logging.h>

/**
 * 登录业务
 * 从json得到用户id
 * 从数据中获取此id的用户,判断此用户的密码是否等于json获取到的密码
 * 判断用户是否重复登录
 * {"msgid":1,"id":13,"password":"123456"}
 * {"errmsg":"this account is using, input another!","errno":2,"msgid":2}
 */
void ChatService::loginHandler(const TcpConnectionPtr &conn, json &js, Timestamp time)
{
    LOG_DEBUG << "do login service!";

    int id = js["id"].get<int>();
    std::string password = js["password"];

    User user = _userModel.query(id);
    if (user.getId() == id && user.getPassword() == password)
    {
        if (user.getState() == "online")
        {
            // 该用户已经登录,不能重复登录
            json response;
            response["msgid"] = LOGIN_MSG_ACK;
            response["errno"] = 2;
            response["errmsg"] = "this account is using, input another!";
            conn->send(response.dump());
        }
        else
        {
            // 登录成功,记录用户连接信息
            // 需要考虑线程安全问题 onMessage会在不同线程中被调用
            {
                lock_guard<mutex> lock(_connMutex);
                _userConnMap.insert({id, conn});
            }

            // id用户登录成功后,向redis订阅channel(id)
            // _redis.subscribe(id); 

            // 登录成功,更新用户状态信息 state offline => online
            user.setState("online");
            _userModel.updateState(user);

            json response;
            response["msgid"] = LOGIN_MSG_ACK;
            response["errno"] = 0;
            response["id"] = user.getId();
            response["name"] = user.getName();

            // 查询该用户是否有离线消息
            std::vector<std::string> vec = _offlineMsgModel.query(id);
            if (!vec.empty())
            {
                response["offlinemsg"] = vec;
                // 读取该用户的离线消息后,将该用户离线消息删除掉
                _offlineMsgModel.remove(id);
            }
            else
            {
                LOG_INFO << "无离线消息";
            }

            std::vector<User> userVec = _friendModel.query(id);
            if (!userVec.empty())
            {
                std::vector<std::string> vec;
                for (auto& user : userVec)
                {
                    json js;
                    js["id"] = user.getId();
                    js["name"] = user.getName();
                    js["state"] = user.getState();
                    vec.push_back(js.dump());
                }
                response["friends"] = vec;
            }

            conn->send(response.dump());
        }
    }
    
}

用户登录模块测试

可以看到返回的错误码:errno = 0表示成功,并在里面返回了好友列表的JSON信息。

在这里插入图片描述

数据库查看:可以看到zhang san是登录的状态了

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值