好友申请同意/拒绝功能
前言
上一集我们就完成了用户信息界面添加好友的功能,我们能够主动对其他用户发送申请添加好友的功能,但是我们仅仅只是实现发送了这个申请的功能,并没有实现获取到对方是否同意/拒绝的功能,所以这一集我们将会介绍如何实现获取好友申请处理结果的功能!
需求分析
我们先要实现在好友申请列表中点击某个元素的同意或拒绝按钮。
如果我们点击接受按钮,我们就会弹出一个消息,好友添加成功,用于提示用户同意了对方的好友申请。
我们就会在这个好友申请列表中删除对应的项,并且能够在好友列表里面看见我们新添加的好友,当然这些好友我们会放置在头部。
如果是点击了拒绝,我们就仅仅只会在申请好友列表中删除对应的项,不会操作我们的好友列表!
当然不仅仅是我们自己能够同意和拒绝,我们申请了好友添加,对方同意或拒绝也是需要实现的!
由于未接入服务端,我们也不能修改数据库中好友关系的原因,我们就如同之前,添加两个按钮用于同意/拒绝好友申请的功能!
当我们点击同意好友申请就会发生以下的事件
我们的好友列表就会添加对方的元素!并通知我们对应的用户同意了的消息!
反之,我们就仅通知我们的用户,对方拒绝了我们的好友申请!不会添加好友到好友列表当中!
这就是我们要实现的功能,那么老规矩,先来看我们要用到的http协议请求响应与URL还有websocket的内容!
这是有关http的内容!
这是有关websocket推送消息的内容!
那么我们就正式开始代码的编写吧!
处理结果方(被申请)
我们这里是处理结果方,我们收到添加好友的申请,我们需要点击同意/拒绝按钮来处理我们好友申请!
客户端
我们的第一步当然是给我们的两个按钮进行信号槽的连接!
connect(acceptBtn, &QPushButton::clicked, this, &ApplyItem::acceptFriendApply);
connect(rejectBtn, &QPushButton::clicked, this, &ApplyItem::rejectFriendApply);
这里我们用分别两个函数进行处理!
当我们点击了这两个按钮,就要发送一个网络请求。
void ApplyItem::acceptFriendApply()
{
//发送网络请求,同意!
DataCenter* dataCenter = DataCenter::getInstance();
//同意申请人的申请!
dataCenter->acceptFriendApplyAsync(this->userId);
//更新界面既包括好友申请列表也包括好友列表,直接放到了主窗口!
}
void ApplyItem::rejectFriendApply()
{
//发送网络请求,拒绝!
DataCenter* dataCenter = DataCenter::getInstance();
dataCenter->rejectFriendApplyAsync(this->userId);
}
两个函数都是一样要通过DataCenter传递loginSessionId给到我们的NetClient。
void DataCenter::acceptFriendApplyAsync(const QString &userId)
{
netClient.acceptFriendApply(loginSessionId, userId);
}
void DataCenter::rejectFriendApplyAsync(const QString &userId)
{
netClient.rejectFriendApply(loginSessionId, userId);
}
我们进入到NetClient,我们这两个函数构造的响应的body就会有所不同,我们请求的区别其实就是一个是否同意!
我们的响应处理的区别就是,当申请结果为同意时,我们不仅仅需要删除好友申请列表对应的项,还需要我们的添加一个新的元素到我们的好友列表当中,当然我们要头插,毕竟是新好友嘛!
当申请结果为拒绝时,我们就仅需要删除好友申请列表对应的项即可!
void NetClient::acceptFriendApply(const QString &loginSessionId, const QString &userId)
{
//构造http请求body
bite_im::FriendAddProcessReq pbReq;
pbReq.setRequestId(makeRequestId());
pbReq.setSessionId(loginSessionId);
pbReq.setAgree(true);
pbReq.setApplyUserId(userId);
QByteArray body = pbReq.serialize(&serializer);
LOG() << "[同意好友申请] 发送请求 requestId=" << pbReq.requestId() << ", loginSessionId=" << pbReq.sessionId()
<<", userId=" << userId;
//发送http请求
QNetworkReply* resp = this->sendHttpRequest("/service/friend/add_friend_process", body);
//处理响应
connect(resp, &QNetworkReply::finished, this, [=](){
bool ok = false;
QString reason;
auto pbResp = this->handleHttpResponse<bite_im::FriendAddProcessRsp>(resp, &ok, &reason);
//判定是否出错
if(!ok){
LOG() << "[同意好友申请]失败!reason=" << reason;
return;
}
//设置数据到DataCenter,好友列表更新,删除好友申请列表的内容
UserInfo applyUser = dataCenter->removeFromApplyList(userId);
QList<UserInfo>* friendList = dataCenter->getFriendList();
friendList->push_front(applyUser);
//发送信号,通知调用
emit dataCenter->acceptFriendApplyDone();
LOG() << "[同意好友申请] 处理响应完毕! requestId=" << pbResp->requestId();
});
}
void NetClient::rejectFriendApply(const QString &loginSessionId, const QString &userId)
{
//构造http请求body
bite_im::FriendAddProcessReq pbReq;
pbReq.setRequestId(makeRequestId());
pbReq.setSessionId(loginSessionId);
pbReq.setAgree(false);
pbReq.setApplyUserId(userId);
QByteArray body = pbReq.serialize(&serializer);
LOG() << "[拒绝好友申请] 发送请求 requestId=" << pbReq.requestId() << ", loginSessionId=" << pbReq.sessionId()
<<", userId=" << userId;
//发送http请求
QNetworkReply* resp = this->sendHttpRequest("/service/friend/add_friend_process", body);
//处理响应
connect(resp, &QNetworkReply::finished, this, [=](){
bool ok = false;
QString reason;
auto pbResp = this->handleHttpResponse<bite_im::FriendAddProcessRsp>(resp, &ok, &reason);
//判定是否出错
if(!ok){
LOG() << "[拒绝好友申请]失败!reason=" << reason;
return;
}
//设置数据到DataCenter,仅删除好友申请列表的内容
dataCenter->removeFromApplyList(userId);
//发送信号,通知调用
emit dataCenter->rejectFriendApplyDone();
LOG() << "[拒绝好友申请] 处理响应完毕! requestId=" << pbResp->requestId();
});
当然,不要杠精啊,这个打印日志的内容肯定是不同的,是需要适用每个请求和响应才行!
我们来看一下删除好友申请列表项的函数
UserInfo DataCenter::removeFromApplyList(const QString &userId)
{
if(applyList == nullptr){
return UserInfo();
}
for(auto it = applyList->begin(); it != applyList->end(); ++it){
if(it->userId == userId){
//复制!
UserInfo toDelete = *it;
applyList->erase(it);
return toDelete;
}
}
return UserInfo();
}
还是很好理解的,我们就是通过迭代器找到对应userId的项即可,我们从申请列表中给踢出去即可!之后返回这个对象的拷贝!
返回这个对象的拷贝就可以直接添加到我们的好友列表!
最后就是发送信号进行更新我们的界面了!
//处理同意好友申请
connect(dataCenter, &DataCenter::acceptFriendApplyDone, this, [=](){
this->updateApplyList();
this->updateFriendList();
Toast::showMessage("好友添加完成!");
});
//处理拒绝好友申请
connect(dataCenter, &DataCenter::rejectFriendApplyDone, this, [=](){
this->updateApplyList();
Toast::showMessage("好友申请已拒绝!");
});
我们都要去更新好友申请列表,我们已经删除了这个元素了,只有当我们的agree为true才需要去更新我们的好友列表!
之后就是都弹出一条信息告诉我们的用户,他们的操作是怎么样的!
这就是客户端的这边的内容!
测试服务端
一样的,两部曲!
第一步:配置路由!
httpServer.route("/service/friend/add_friend_process", [=](const QHttpServerRequest& req){
return this->addFriendProcess(req);
});
第二步:解析请求,构造响应,之后发送给客户端!
QHttpServerResponse HttpServer::addFriendProcess(const QHttpServerRequest &req)
{
//解析请求
bite_im::FriendAddProcessReq pbReq;
pbReq.deserialize(&serializer, req.body());
LOG() << "[REQ 添加好友申请处理] requestId=" << pbReq.requestId() << ", loginSessionId=" << pbReq.sessionId()
<<", applyUserId=" << pbReq.applyUserId() << ", agree=" << pbReq.agree();
//构造响应
bite_im::FriendAddProcessRsp pbResp;
pbResp.setRequestId(pbReq.requestId());
pbResp.setSuccess(true);
pbResp.setErrmsg("");
pbResp.setNewSessionId("");
QByteArray body = pbResp.serialize(&serializer);
//构造http响应
QHttpServerResponse resp(body, QHttpServerResponse::StatusCode::Ok);
resp.setHeader("Content-Type", "application/x-protobuf");
return resp;
}
就这样,我们处理结果方的功能就实现了!
等待结果方(申请)
那么完成了处理结果方,我们就来完成等待结果方的内容!
测试服务端
我们首先就是给UI界面拖两个按钮,一个用于同意,一个用于拒绝!
之后转到槽,我们只要点击了就可以触发!
相同的,我们要通过获取Websocket实例,并通过发送信号来获取到socket对象,当然,我们这里由于是不同的两个操作,所以我们需要在信号槽传入一个bool类型的参数,用于区分两个不同的处理结果!
void Widget::on_pushButton_4_clicked()
{
WebsocketServer* websocketServer = WebsocketServer::getInstance();
emit websocketServer->sendAddFriendProcess(true);
}
void Widget::on_pushButton_5_clicked()
{
WebsocketServer* websocketServer = WebsocketServer::getInstance();
emit websocketServer->sendAddFriendProcess(false);
}
之后就是构造一个假数据,当然我们需要参考我们的proto文件的内容。之后我们就要通过二进制的形式发送给到我们的客户端,我们客户端的NetClient就可以获取到我们websocket推送的通知!
//发送添加好友申请结果
connect(this, &WebsocketServer::sendAddFriendProcess, this, [=](bool agree){
if(socket == nullptr || !socket->isValid()){
LOG() << "socket对象无效!";
return;
}
bite_im::NotifyMessage notifyMessage;
notifyMessage.setNotifyEventId("");
notifyMessage.setNotifyType(bite_im::NotifyTypeGadget::NotifyType::FRIEND_ADD_PROCESS_NOTIFY);
QByteArray avatar = loadFileToByteArray(":/resource/image/groupAvatar.png");
bite_im::UserInfo userInfo = makeUserInfo(67940, avatar);
bite_im::NotifyFriendAddProcess friendAddProcess;
friendAddProcess.setUserInfo(userInfo);
friendAddProcess.setAgree(agree);
notifyMessage.setFriendProcessResult(friendAddProcess);
QByteArray body = notifyMessage.serialize(&serializer);
socket->sendBinaryMessage(body);
LOG() << "通知好友申请处理结果 userId=67940, agree=" << agree;
});
当然这里会区分我们的agree,同一个函数就可以处理!
还是相同的!一定记得主动断开!
disconnect(this, &WebsocketServer::sendAddFriendProcess, this, nullptr);
客户端
之后我们就可以在客户端的NetClient接收到我们websocket推送过来的二进制数据了!
还是和之前一样,我们会通过handleWsResponse函数判定不同通知类型的处理方式,并从中获取关键数据来进一步处理我们的界面以及数据!
else if(notifyMessage.notifyType() == bite_im::NotifyTypeGadget::NotifyType::FRIEND_ADD_PROCESS_NOTIFY){
//添加好友申请结果处理通知
UserInfo userInfo;
userInfo.load(notifyMessage.friendProcessResult().userInfo());
bool agree = notifyMessage.friendProcessResult().agree();
handleWsAddFriendProcess(userInfo, agree);
这里比较关键的就是对应用户的相关信息,以及我们的处理结果!
这里的用户相关信息其实我们主要是用于保存相关信息到好友列表中以及提示我们的用户是哪位用户同意/拒绝了你的好友申请!
void NetClient::handleWsAddFriendProcess(const model::UserInfo &userInfo, bool agree)
{
if(agree){
//对方同意了!
QList<UserInfo>* friendList = dataCenter->getFriendList();
if(friendList == nullptr){
LOG() << "客户端未加载好友列表!";
return;
}
friendList->push_front(userInfo);
//同时还要更新一下界面
emit dataCenter->receiveFriendProcessDone(userInfo.nickname, agree);
}else{
//没同意!
emit dataCenter->receiveFriendProcessDone(userInfo.nickname, agree);
}
}
我们的处理结果为同意就需要将这个用户信息保存到我们的好友列表当中!
之后就要发送一个信号用于更新我们的界面!
如果是同意,就更新好友列表,如果是拒绝,就不需要更新!
但是我们要提示我们的用户处理结果!
//处理好友结果的推送数据
connect(dataCenter, &DataCenter::receiveFriendProcessDone, this, [=](const QString& nickname, bool agree){
if(agree){
//同意
this->updateFriendList();
Toast::showMessage(nickname + "同意了你的好友申请");
}else{
//拒绝
Toast::showMessage(nickname + "拒绝了你的好友申请");
}
});
那么这一切就已经完成!这就是好友申请同意/拒绝功能!
这一集就先到这里吧!