[集群聊天服务器]----(八)群组类、群组操作接口以及业务模块之创建群组,加入群组以及群组聊天

接着上文关于[集群聊天服务器]----(七)业务模块之一对一聊天、添加好友函数、好友类以及离线消息类的剖析。本章将对创建群组,加入群组以及群组聊天业务进行剖析。

群类

类似于User类,构建了Group类

#ifndef GROUP_H
#define GROUP_H#include "groupuser.hpp"
#include <string>
#include <vector>
using namespace std;//User表的ORM类
class Group
{
public:Group(int id = -1, string name = "", string desc = ""){this->id = id;this->name = name;this->desc = desc;}void setId(int id) {this->id=id;}void setName(string name) {this->name=name;}void setDesc(string desc) {this->desc=desc;}int getId() {return this->id;}string getName() {return this->name;}string getDesc() {return this->desc=desc;}  //组功能描述vector<GroupUser> &getUsers() {return this->users;}private:int id;string name;string desc;vector<GroupUser> users; //组成员
};#endif
  • 群的id初始默认为-1,设置/获取群id,群名称以及群用途函数

GroupUser类

GroupUser为群组用户,继承了User类,多了一个role角色信息,从User类直接继承,复用User的其他信息

void setRole(string role) {this->role = role;}
string getRole() {return this->role;}//派生类的特殊变量 role角色
string role;

群组信息的操作接口

// 创建群组
bool createGroup(Group &group);// 加入群组
void addGroup(int userid, int groupid, string role);// 查询用户所在群组信息
vector<Group> queryGroups(int userid);// 根据指定的groupid查询群组用户id列表,除userid自己,主要用户群聊业务给群组其它成员群发消息
vector<int> queryGroupUsers(int userid, int groupid);

创建群组函数

bool GroupModel::createGroup(Group &group)
{char sql[1024] = {0};sprintf(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;
}
  • 组装sql语句,根据群名称,群作用在allgroup表插入相关消息;
  • 连接数据库,并进行更新,并返回群id

加入群组函数

void GroupModel::addGroup(int userid, int groupid, string role)
{char sql[1024] = {0};sprintf(sql, "insert into groupuser values(%d,%d,'%s')",groupid,userid,role.c_str());MySQL mysql;// 连接数据库if (mysql.connect()){// 更新数据库语句mysql.update(sql);}
}
  • 组装sql语句,根据群id,用户id,以及群内角色在allgroup表插入相关消息;
  • 连接数据库,并进行更新,并返回群id

查询用户所在群组信息

vector<Group> GroupModel::queryGroups(int userid)
{char sql[1024] = {0};sprintf(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);vector<Group> groupVec;MySQL mysql;if (mysql.connect()){// 更新数据库语句MYSQL_RES *res = mysql.query(sql); // 指针 内部动态内存开辟 需要释放资源if (res != nullptr){// 获取行 根据主键查MYSQL_ROW row ;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){sprintf(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;
}
  • 组装sql语句,根据用户id在allgroup表和groupuser表中进联合查找,寻找用户所在的组;
  • 根据sql语句,调用MySQL::query()语句进行查找好友,然后调用mysql_fetch_row()函数,查找对应的行,row是MYSQL_ROW类型,可以根据下标找到对应的值,并把用户对应的组Group类放入groupVec中;
  • 根据groupVec中,对组内的成员姓名,id以及状态和群内角色进行查找,对应的GroupUser类进行返回
  • 注意释放资源

查找群内除userid以外的用户

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;
}
  • 组装sql语句,根据userid在groupuser表查找其余用户id;
  • 根据sql语句,调用MySQL::query()语句进行查找好友,然后调用mysql_fetch_row()函数,查找对应的行,row是MYSQL_ROW类型,可以根据下标找到对应的值,并把用户放入idVec中返回;
  • 注意释放资源

创建群组

当客户端输入msgid=CREATE_GROUP_MSG时,ChatService::ChatService()中会回调ChatService::createGroup()函数进行处理:

void ChatService::createGroup(const TcpConnectionPtr &conn, json &js, Timestamp time)
{int userid = js["id"].get<int>();string name = js["groupname"];string desc = js["groupdesc"];// 存储新创建的群组信息Group group(-1, name, desc);if (_groupModel.createGroup(group)){// 存储群组创建人信息_groupModel.addGroup(userid, group.getId(), "creator");}
}
  • 通过 JSON 对象反序列结果,寻找用户id userid对应的值,groupname以及groupdesc
  • 创建Group类,并调用 GroupModel::createGroup()创建群,角色为creator;
  • 根据创建的群组,设置群id

加入群组

当客户端输入msgid=ADD_GROUP_MSG时,ChatService::ChatService()中会回调ChatService::addGroup()函数进行处理:

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");}
  • 根据userid以及要加入的groupid,调用GroupModel::addGroup()函数加入群,角色默认为normal;

群组聊天

当客户端输入msgid=GROUP_CHAT_MSG时,ChatService::ChatService()中会回调ChatService::groupChat()函数进行处理:

void ChatService::groupChat(const TcpConnectionPtr &conn, json &js, Timestamp time)
{int userid = js["id"].get<int>();int groupid = js["groupid"].get<int>();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()){// id 在线 转发消息 服务器主动推送消息给toid用户it->second->send(js.dump());}else{User user = _userModel.query(id);//在另一台电脑上if (user.getState() == "online"){_redis.publish(id, js.dump());}else{// id 不在线 存储离线消息_offlineMsgModel.insert(id, js.dump());}        }}
}
  • 通过 JSON 对象反序列结果,寻找用户id以及群id对应的值,找到用户想要对话的群,并在_groupModel中进行查找群内其余成员,并放入useridVec中;
  • _userConnMap查找用户是否存在;
  • 如果用户在一台主机并且处于在线状态,就发送想要发送的消息;
  • 如果不在同一台主机,根据id调用_userModel在user表中进行查看对方是否在线,如果在线就通过redis发布消息
  • 不在线就存储其离线消息

好了~ 关于群组类、群组操作接口以及业务模块之创建群组,加入群组以及群组聊天的剖析就到此结束了,服务端的开发也到此结束了,接下来我们会剖析客户端的实现,下一节见~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/16442.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在Windows中安装Redis

一、下载Redis github链接&#xff1a;https://github.com/redis-windows/redis-windows/releases 二、安装 解压后点击start.bat文件即可启动服务 新开一个cmd窗口进入安装了Redis的文件夹输入redis-cli.exe -h 127.0.0.1 -p 6379连接Redis&#xff0c;见如下结果便是成功&…

sql-labs靶场环境搭建(手把手保姆级教学)

文章目录 一、sql-labs靶场简介&#xff1a;二、搭建过程1、资源下载2、配置文件&#xff1b;3、访问网站4、创建数据库 三、使用PhpStudy2018原因 一、sql-labs靶场简介&#xff1a; SQL-Labs 是一个实践环境&#xff0c;旨在用于数据库和 SQL&#xff08;结构化查询语言&…

某大型制造集团企业信息化建设总体规划设计方案(67页PPT)

方案介绍&#xff1a; 随着信息技术的飞速发展&#xff0c;企业信息化建设已成为提高管理效率、增强企业竞争力的重要手段。某大型制造集团为应对市场变化、提升管理水平、优化资源配置&#xff0c;决定进行全面深入的信息化建设。本方案旨在构建一个集生产、管理、销售、物流…

Java中的IO和NIO(New IO)有什么区别?

在Java编程中&#xff0c;IO&#xff08;Input/Output&#xff09;和NIO&#xff08;New IO&#xff09;是两个重要的概念&#xff0c;它们分别代表了Java中的传统IO和新的IO库。为了全面解释这两者之间的区别&#xff0c;我们将从技术难点、面试官关注点、回答吸引力和代码举例…

【DevOps】Jenkins + Dockerfile自动部署Maven(SpringBoot)项目

环境 docker_host192.168.0.1jenkins_host192.168.0.2 jenkins_host构建完成后把jar发布到docker_host&#xff0c;再通过dockerfile自动构建镜像&#xff0c;运行镜像 1 Jenkins安装 AWS EC2安装Jenkins&#xff1a;AWS EC2 JDK11 Jenkins-CSDN博客 AWS EC2上Docker安装…

T113调试7寸RGB屏

文章目录 软硬件介绍软件板卡屏幕 调试修改内核设备树修改U-Boot设备树 测试添加启动logo其它问题总结 软硬件介绍 软件 基于Tina5.0 SDK。 板卡 韦东山的T113工业板&#xff1a; 屏幕 韦东山的7寸RGB电容触摸屏&#xff1a; 调试 修改内核设备树 打开内核设备树<…

代码随想录算法训练营第四天| 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点 、 面试题 02.07. 链表相交、142.环形链表II

24. 两两交换链表中的节点 题目链接&#xff1a; 24. 两两交换链表中的节点 文档讲解&#xff1a;代码随想录 状态&#xff1a;没做出来&#xff0c;没有正确更新头节点&#xff0c;因为head和cur共享引用&#xff0c;会随着cur的移动&#xff0c;丢失之前存放的节点 错误代码&…

efuse xinpian

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 xx项目需要进行efuse烧录&#xff0c;之前都是单板环境&#xff0c;现补充裸板烧录教…

Java计算时间相差多少秒/localdatetime计算时间差

1、常用的计算时间差方法&#xff1f; 【将字符串的时间转化成LocalDateTime】 String time1"2024-01-01 10:25:10";LocalDateTime starttime1 LocalDateTime.parse(time1, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));【LocalDateTime计算时…

51单片机-实机演示(按键)

书接上回。http://t.csdnimg.cn/4wSSW 目录 一.按下灭&#xff0c;松开亮 二.两个按键控制两个灯 三.点一下灯开&#xff0c;在按一下关 四。优化按键消抖 1.加入bit变量 一.按下灭&#xff0c;松开亮 代码 #include <reg52.h> //此文件中定义了单片机的一些特…

自定义函数python:深入解析与实操

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言&#xff1a;函数的命名与规范 二、函数命名&#xff1a;遵循规范&#xff0c;易于…

利用阅读APP3.0目录展示要查看的内容01

喜欢读电子书的小伙伴往往会遇到一个问题&#xff0c;就是想要看书中某些内容&#xff0c;但是不知道具体章节&#xff0c;所以就用查找功能来查&#xff0c;但是呢查找功能查出来展示的结果并不直观。 比如想要阅读:青竹蜂云剑&#xff0c;大衍决&#xff0c;南宫婉&#xff0…

【wpf】关于焦点

背景 今天踩了一个坑。我用到handycontrol中的一个密码控件PasswordBox <hc:PasswordBox x:Name"pb" hc:TitleElement.Title"密码" hc:TitleElement.TitlePlacement"Left" Width"120"></hc:PasswordBox>然后想实现一个回…

基于springboot的在线宠物用品交易网站源码数据库

基于springboot的在线宠物用品交易网站源码数据库 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了在线宠物用品交易网站的开发全过程。通过分析在线宠物用品交易网站管理的不足&#xff0c;创建了一个计算机管理在…

265 基于matlab的粒子群优化分数阶灰色预测模型

基于matlab的粒子群优化分数阶灰色预测模型&#xff0c;以误差结果为目标进行预测&#xff0c;输出多个预测结果。并输出迭代曲线。程序已调通&#xff0c;可直接运行。 265 分数阶灰色预测 粒子群优化算法 - 小红书 (xiaohongshu.com)

二叉树——经典练习题

目录 前言&#xff1a; 一、单值二叉树 题目描述&#xff1a; 思路分析&#xff1a; 代码实现&#xff1a; 二、二叉树最大深度 题目描述&#xff1a; 思路分析&#xff1a; 代码实现&#xff1a; 三、检查两颗树是否相同 题目描述&#xff1a; 思路分析&#xff1a; 代…

用C语言设计轨道电机的驱动库

一、设计目的 设计能驱动立体轨道电机的抽象驱动程序库。 二、设计要求 命名规范。设计简单&#xff0c;方便使用。体积小。满足电机的移动、停止、初始化、恢复等控制&#xff0c;甚至通过网络控制。 三、设计内容 (一)属性封装 1、定义配置结构体 // 用于配置参数 typed…

线程和进程和synchronized

进程&#xff08;Process&#xff09;是系统进行资源分配和调度的一个独立单位&#xff0c;是程序的一次执行过程&#xff0c;具有自己的地址空间和文件描述符等资源。每个进程都有独立的地址空间和资源&#xff0c;因此创建和销毁进程的开销相对较大。进程之间通过IPC&#xf…

leetcode打卡#day36 1005. K 次取反后最大化的数组和、134. 加油站、135. 分发糖果

1005. K 次取反后最大化的数组和 class Solution { private://将数组元素按绝对值从大到小排列static bool cmp(int a, int b) {return abs(a) > abs(b);} public:int largestSumAfterKNegations(vector<int>& nums, int k) {//对数据进行排序sort(nums.begin(),…

方法引用(进一步简化Lambda)

静态方法的引用 格式&#xff1a;类名::静态方法。 场景&#xff1a;如果某个Lambda表达式里只是调用一个静态方法&#xff0c;并且前后参数的形式一致&#xff0c;就可以使用静态方法引用。 //静态方法的引用 Arrays.sort(cooking, CompareByData::compareByPrice);public …