• (十二)群组业务


    群组表的设计

    **AllGroup表 **

    字段名称字段类型字段说明约束
    idINT组idPRIMARY KEY、AUTO_INCREMENT
    groupnameVARCHAR(50)组名称NOT NULL, UNIQUE
    groupdescVARCHAR(200)组功能描述DEFAULT ‘’

    **GroupUser表 **

    字段名称字段类型字段说明约束
    groupidINT组idNOT NULL、联合主键
    useridINT组员idNOT NULL、联合主键
    grouproleENUM(‘creator’, ‘normal’)组内角色DEFAULT ‘normal’

    GroupUserModel

    GroupUser

    #ifndef __GROUP_USER_H__
    #define __GROUP_USER_H__
    
    #include "user.hpp"
    #include 
    
    class GroupUser : public User
    {
    public:
        GroupUser() = default;
        void setRole(const std::string& role) { _role = role; }
        std::string getRole() { return _role; }
    
    private:
        std::string _role;
    };
    
    
    #endif // __GROUP_USER_H__
    

    GroupModel

    #ifndef __GROUP_MODEL_H
    #define __GROUP_MODEL_H
    
    #include "group.hpp"
    #include 
    #include 
    
    class GroupModel
    {
    public:
        // 创建群组
        bool createGroup(Group &group);
        // 加入群组
        void addGroup(int userid, int groupid, std::string role);
        // 查询用户所在群组信息
        std::vector<Group> queryGroups(int userid);
        // 根据指定的groupid查询群组用户id列表,除userid自己,主要用户群聊业务给群组其它成员群发消息
        std::vector<int> queryGroupUsers(int userid, int groupid);
    };
    
    #endif // __GROUP_MODEL_H
    
    #include "group_model.hpp"
    #include "db.h"
    
    // 创建群组(设置群组名字和描述)
    bool GroupModel::createGroup(Group &group)
    {
        char sql[1024] = {0};
        snprintf(sql, sizeof(sql), "insert into allgroup(groupname, groupdesc) values('%s', '%s')",
            group.getName().c_str(), group.getDesc().c_str());
        
        MySQL mysql;
        if (mysql.connect())
        {
            if (mysql.update(sql))
            {
                group.setId(mysql_insert_id(mysql.getConnection()));
                return true;
            }
        }
    
        return false;
    }
    
    // 加入群组(用户ID 加入群组ID 在群组角色)
    void GroupModel::addGroup(int userid, int groupid, std::string role)
    {
        char sql[1024] = {0};
        snprintf(sql, sizeof(sql), "insert into groupuser values(%d, %d, '%s')",
            groupid, userid, role.c_str());
        
        MySQL mysql;
        if (mysql.connect())
        {
            mysql.update(sql);
        }
    }
    
    // 查询用户所在群组信息
    std::vector<Group> GroupModel::queryGroups(int userid)
    {
        /**
         * // TODO:MySQL联表查询
         * 1. 先根据userid在groupuser表中查询出该用户所属的群组信息
         * 2. 再根据群组信息,查询属于该群组的所有用户的userid,并且和user表进行多表联合查询,查出用户的详细信息
        */
        char sql[1024] = {0};
        snprintf(sql, sizeof(sql), "select a.id,a.groupname,a.groupdesc from allgroup a inner join \
            groupuser b on a.id = b.groupid where b.userid=%d",
            userid);
        
        std::vector<Group> groupVec;
    
        MySQL mysql;
        if (mysql.connect())
        {
            MYSQL_RES *res = mysql.query(sql);
            if (res != nullptr)
            {
                MYSQL_ROW row;
                // 查出userid所有的群组信息
                while ((row = mysql_fetch_row(res)) != nullptr)
                {
                    Group group;
                    group.setId(atoi(row[0]));
                    group.setName(row[1]);
                    group.setDesc(row[2]);
                    groupVec.push_back(group);
                }
                mysql_free_result(res);
            }
        }
    
        // 查询群组的用户信息
        for (Group &group : groupVec)
        {
            snprintf(sql, sizeof(sql), "select a.id,a.name,a.state,b.grouprole from user a \
                inner join groupuser b on b.userid = a.id where b.groupid=%d",
                    group.getId());
    
            MYSQL_RES *res = mysql.query(sql);
            if (res != nullptr)
            {
                MYSQL_ROW row;
                while ((row = mysql_fetch_row(res)) != nullptr)
                {
                    GroupUser user;
                    user.setId(atoi(row[0]));
                    user.setName(row[1]);
                    user.setState(row[2]);
                    user.setRole(row[3]);
                    group.getUsers().push_back(user);
                }
                mysql_free_result(res);
            }
        }
        return groupVec;
    }
    
    // 根据指定的groupid查询群组用户id列表,除userid自己,主要用户群聊业务给群组其它成员群发消息
    std::vector<int> GroupModel::queryGroupUsers(int userid, int groupid)
    {
        char sql[1024] = {0};
        sprintf(sql, "select userid from groupuser where groupid = %d and userid != %d", groupid, userid);
    
        vector<int> idVec;
        MySQL mysql;
        if (mysql.connect())
        {
            MYSQL_RES *res = mysql.query(sql);
            if (res != nullptr)
            {
                MYSQL_ROW row;
                while ((row = mysql_fetch_row(res)) != nullptr)
                {
                    idVec.push_back(atoi(row[0]));
                }
                mysql_free_result(res);
            }
        }
        return idVec;  
    }
    
    

    群组业务代码

    创建群组业务代码

    // 创建群组业务
    void ChatService::createGroup(const TcpConnectionPtr &conn, json &js, Timestamp time)
    {
        int userId = js["id"].get<int>();
        std::string name = js["groupname"];
        std::string desc = js["groupesc"];
    
        // 存储新创建的群组消息
        Group group(-1, name, desc);
        if (_groupModel.createGroup(group))
        {
            // 存储群组创建人信息
            _groupModel.addGroup(userId, group.getId(), "creator");
        }
    }
    

    加入群组业务代码

    // 加入群组业务
    void ChatService::addGroup(const TcpConnectionPtr &conn, json &js, Timestamp time)
    {
        int userId = js["id"].get<int>();
        int groupId = js["groupid"].get<int>();
        _groupModel.addGroup(userId, groupId, "normal");
    }
    

    群组聊天业务代码

    // 群组聊天业务
    void ChatService::groupChat(const TcpConnectionPtr &conn, json &js, Timestamp time)
    {
        int userId = js["id"].get<int>();
        int groupId = js["groupid"].get<int>();
        std::vector<int> userIdVec = _groupModel.queryGroupUsers(userId, groupId);
    
        lock_guard<mutex> lock(_connMutex);
        for (int id : userIdVec)
        {
            auto it = _userConnMap.find(id);
            if (it != _userConnMap.end())
            {
                // 转发群消息
                it->second->send(js.dump());
            }
            else
            {
                // 查询toid是否在线
                User user = _userModel.query(id);
                if (user.getState() == "online")
                {
                    // 向群组成员publish信息
                    _redis.publish(id, js.dump());
                }
                else
                {
                    //转储离线消息
                    _offlineMsgModel.insert(id, js.dump());
                }
            }
        }
    }
    

    群组业务测试

    创建群组测试

    这是之前的所有群组
    在这里插入图片描述

    登录张三的用户,创建了两个学习群组。Java和PHP
    在这里插入图片描述

    ![![1663821199(1).png](https://img-blog.csdnimg.cn/img_convert/c0d5d70b44ac3c57713fa8c9ccac671f.png#clientId=u8680f703-f02f-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=224&id=u68b971af&margin=[object Object]&name=1663821199(1).png&originHeight=280&origin &originalType=binary&ratio=1&rotation=0&showTitle=false&size=12073&status=done&style=none&taskId=u11d6ce6a-2b5a-43a2-9ed1-](https://img-blog.csdnimg.cn/7506e77c464a44b986b5a273a8a468e5.png)
5ac74fbc731&title=& .6)

    加入群组测试

    登录新的用户,加入群组13

    {"msgid":1008,"id":15,"groupid":13}
    

    在这里插入图片描述

    还是有一些问题的,比如重复让同一成员加入群组,这里不会提示报错,看日后迭代吧。

    群组聊天测试

    在这里插入图片描述

  • 相关阅读:
    安卓学习中遇到的问题【bug】
    MybatisPlus
    Vitepress搭建组件库文档(下)—— 组件 Demo
    K8S之Flannel的vxlan网络模式初步源码解析
    《算法设计与分析(第4版)》笔记——第 1 章 算法入门
    Java虚拟机运行时数据区结构详解
    【代码源每日一题Div1】好序列/BZOJ4059「启发式分治」
    【ftp篇】 vsftp(ftp) 每天生成一个动态密码
    正则表达式
    自动化测试中临时数据如何保存 ?这里提供一个简单又好用的第三方包 ,可以放弃redis了。
  • 原文地址:https://blog.csdn.net/weixin_46272577/article/details/127093716