日期:2025.4.24

学习内容:

  • 解决了聊天窗口的问题
  • 修复了"没有区分好友或者群聊的聊天窗口"的bug
  • 修复了"群聊消息undefined"的bug

个人总结:

我真的希望是最后的几次里去学习前端的一些知识,其实我更多的是能够感觉到前端的代码我不会写,有一些东西还不太了解,导致目前这些想法我不是太实现的出来,不过个人觉得其实上手确实不算慢的,关于实现修复了"没有区分好友或者群聊的聊天窗口"的bug这个内容,我是一开始想直接无脑AI,结果发现弱智AI解决不了,我只能静下心来去搞,发现其实并不是那么的困难 (当然也有可能是本来这个就不难,是我太傻)。

修复了聊天窗口的bug

其实这个并不麻烦,直接让AI给我跑一个 (还是借助了AI的力量。

 /* 聊天区域 */
.chat-pane {
display: flex;
flex-direction: column;
height: 100vh; /* 占据全屏高度 */
}

修复了"没有区分好友或者群聊的聊天窗口"的bug

有一些恶心了,首先我们肯定是要跟开一个map一样,存下来客户单和每一个用户的聊天记录

export const chatSessions = new Map();
export const chatSessionsGruop = new Map();

就像这样,开了两个,第一个是和用户的,第二个是和群聊的。

这里就展开讲一个了,毕竟几乎一模一样。

我们先把问题拆解一下:

我们肯定要实现,当我们发送消息or接收消息的时候,需要把这个消息存起来,那是发送还是接受的时候呢?应该是接收消息的时候,毕竟我们发送消息的时候,程序的设计里,我们相当于是给自己也发送了个消息。

先看一下handler的改动:

 //处理接收到的消息
16: (data) => {
const messagesDiv = document.getElementById("chat-messages"); messagesDiv.appendChild(createMessageElement(data));
// 自动滚动到底部
messagesDiv.scrollTop = messagesDiv.scrollHeight; //把消息放进session里;
if (data.hasOwnProperty("group_id")) {
const id = parseInt(data.group_id);
if (!chatSessionsGruop.has(id)) {
chatSessionsGruop.set(id, []);
console.log("set group good", id);
}
chatSessionsGruop.get(id).push(data);
} else {
//是自己给别人发送的消息,应该是记录在别人to_id的聊天里
const id =
parseInt(data.from_id) === parseInt(storedUser.id)
? parseInt(data.to_id)
: parseInt(data.from_id); if (!chatSessions.has(id)) {
chatSessions.set(id, []);
console.log("set user good", id, typeof id);
}
chatSessions.get(id).push(data);
}
},

这里我挨个来讲一下,首先,前面三条和之前的一样,为了简略一些,把那些创建消息的内容写进去了一个函数里:

export function createMessageElement(data) {
const messageDiv = document.createElement("div");
messageDiv.className = `message ${
data.hasOwnProperty("from_id")
? data.from_id === storedUser.id
? "self"
: ""
: data.user_id === storedUser.id
? "self"
: ""
}`;
messageDiv.innerHTML = `
<div class="content">${data.text}</div>
<div class="message-time">
${data.time}
</div>
`;
return messageDiv;
}

然后我们需要把接受到的消息放到session里,这里要区分一下,我们只讨论与用户的聊天:对于当前的客户端来说,如果发送消息的人是自己的话,那么我们就把消息记录到接收消息的人的聊天里,如果自己是接收消息的人,就要把消息记录到发送消息的人的聊天里。

 	if (!chatSessions.has(id)) {
chatSessions.set(id, []);
console.log("set user good", id, typeof id);
}
chatSessions.get(id).push(data);

这里是在说:如果我们的容器里没有id的话,那么我们就创建一个,log是我调试用的,然后get到id的key并且push。

群聊我们倒是不用太怎么判断了,毕竟都是存到群聊的聊天记录里。

现在我们已经把消息存好了,那消息的读取,是应该在我们点击好友或者群聊的时候处理的:

找到我们写的点击好友时发生的回调函数:


import { FriendListHandler } from "./friendListView.js";
export const friendListView = new FriendListHandler(
"chat-list",
(selectedFriend) => {
// 这里处理选中好友后的逻辑 currentChat.value = {
type: "friend",
id: parseInt(selectedFriend.id),
name: selectedFriend.name,
}; // 清空聊天区域
const messagesDiv = document.getElementById("chat-messages");
messagesDiv.innerHTML = "";
const sessionid = parseInt(currentChat.value.id);
// 加载历史消息
if (chatSessions.has(sessionid)) {
console.log("YES");
chatSessions.get(sessionid).forEach((msg) => {
messagesDiv.appendChild(createMessageElement(msg));
messagesDiv.scrollTop = messagesDiv.scrollHeight;
});
} else {
console.log("NO", sessionid);
} // 更新聊天窗口标题
document.querySelector(
".chat-header"
).textContent = `与 ${currentChat.value.name} 的对话`;
}
);

这里多了中间的部分,分别是清空聊天区域,然后加载我们的历史消息。

如果存在历史消息的话,就把每一个消息给输出出来。

我们也用同样的办法来处理群聊就好了。

但是我们还要处理一个烂摊子,正如我们当时要加一个CHAT_TO_ONE_ACK一样,我们当时的偷懒,现在需要重新修改一下muduo服务端的内容,添加一个CHAT_TO_GROUP_ACK。

所以大概就是加了一些代码:

int user_id = js["user_id"].get<int>();
// std::string user_name = js["user_name"].get<std::string>();
int group_id = js["group_id"].get<int>();
Group group = _group_model.GetGroup(group_id);
User user = _user_modle.Query(user_id); json response;
response["user_id"] = user_id;
response["user_name"] = user.GetName();
response["group_id"] = group_id;
response["group_name"] = group.GetName(); //...
if (it != _conn_mp.end())
{
auto to_conn = it->second.getConn();
response["uid"] = it->second.getUid(); Send(to_conn, response.dump());
continue;
}

与此同时,我们的前端也要改一下:

 //处理接收到的好友发来的消息
16: (data) => {
if (
currentChat.value.type === "friend" &&
(data.from_id === storedUser.id || data.from_id === currentChat.value.id)
) {
const messagesDiv = document.getElementById("chat-messages"); messagesDiv.appendChild(createMessageElement(data));
// 自动滚动到底部
messagesDiv.scrollTop = messagesDiv.scrollHeight;
} //把消息放进session里; //是自己给别人发送的消息,应该是记录在别人to_id的聊天里,否则就是记录到from_id里。
const id =
parseInt(data.from_id) === parseInt(storedUser.id)
? parseInt(data.to_id)
: parseInt(data.from_id); if (!chatSessions.has(id)) {
chatSessions.set(id, []);
console.log("set user good", id, typeof id);
}
chatSessions.get(id).push(data);
},
//处理接收到的群聊发来的消息
19: (data) => {
if (
currentChat.value.type === "group" &&
(parseInt(data.from_id) === parseInt(storedUser.id) ||
data.group_id === currentChat.value.id)
) {
const messagesDiv = document.getElementById("chat-messages"); messagesDiv.appendChild(createMessageElement(data));
// 自动滚动到底部
messagesDiv.scrollTop = messagesDiv.scrollHeight;
} //把消息放进session里; const id = parseInt(data.group_id);
if (!chatSessionsGruop.has(id)) {
chatSessionsGruop.set(id, []);
console.log("set group good", id);
}
chatSessionsGruop.get(id).push(data);
},

这里加了个东西,就是判断

if (
currentChat.value.type === "friend" &&
(data.from_id === storedUser.id || data.from_id === currentChat.value.id)
)

如果当前的接受的消息是我们目前的聊天窗口,我们才会显示这条信息。

群聊那边也是如此。

至此,我们就实现了基本的好友聊天和群里聊天的功能。

but我现在发现,我实现了之后,群聊里接受的消息是undefined。

修复了群聊消息undefined的bug

ok,先说一下,在找bug的时候,突然发现,如果有一方的currentChat是null的话,那么对方发送的消息将不会记录到聊天记录里面。

于是我们要在push之前加一个判断是否为null

大概就是这样:

if (currentChat.value != null)
if (
currentChat.value.type === "group" &&
(parseInt(data.from_id) === parseInt(storedUser.id) ||
data.group_id === currentChat.value.id)
) {
const messagesDiv = document.getElementById("chat-messages"); messagesDiv.appendChild(createMessageElement(data));
// 自动滚动到底部
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}

关于undefined,原来是因为我服务端的response里忘了装text和time了,怪不得undefined呢。

然后又对于消息的弹出做了一点点改变:

// 新增消息元素创建函数
export function createMessageElement(data) {
const messageDiv = document.createElement("div");
if (data.hasOwnProperty("group_id")) {
messageDiv.className = `message ${
data.user_id === storedUser.id ? "self" : ""
}`;
messageDiv.innerHTML = `
<div class="content">${data.text}</div>
<div class="message-user ${
data.user_id === storedUser.id ? "self" : ""
}">${data.user_name}</div>
<div class="message-time">
${data.time}
</div>
`;
} else {
messageDiv.className = `message ${
data.from_id === storedUser.id ? "self" : ""
}`;
messageDiv.innerHTML = `
<div class="content">${data.text}</div>
<div class="message-time">
${data.time}
</div>
`;
} return messageDiv;
}

直接分开讨论群聊还是好友了,毕竟群聊的显示内容和好友的不太一样,一直用三目运算符有点麻烦。

已经活成了一个码农

顺便加了个css:

	 .message-user.self {
font-size: 16px;
color: #00fc2a;
margin-top: 4px;
}
.message-user {
font-size: 16px;
color: #ca2e2e;
margin-top: 4px;
}

所以到这里为止,终于成功实现了群聊和好友的发消息的内容。

postscript

至此为止,我们已经完成了关于昨晚写的大部分的功能,除了那个状态刷新,但我觉得可能没必要吧。

所以暂时决定就完成到这里,后续的todo大概有这些:

  • 添加好友
  • 添加群聊
  • 创建群聊
  • 注册功能

完成这四个之后,目前来说就没有前端可以做的事情了。我们后续的重心将落在后端上。

【work记录:c++web聊天服务器】解决了聊天窗口的问题|修复了"没有区分好友或者群聊的聊天窗口"的bug|修复了"群聊消息undefined"的bug的更多相关文章

  1. IM服务器:我的千万级在线聊天服务器集群

    一.服务器特点 01.傻瓜式部署,一键式启动: 02.单机支持10万以上在线用户聊天(8G内存,如果内存足够大,并发量可超过10万): 03.支持服务器集群,集群间高内聚.低耦合,可动态横向扩展IM服 ...

  2. 看完这篇包你进大厂,实战即时聊天,一文说明白:聊天服务器+聊天客户端+Web管理控制台。

    一.前言 说实话,写这个玩意儿是我上周刚刚产生的想法,本想写完后把代码挂上来赚点积分也不错.写完后发现这东西值得写一篇文章,授人予鱼不如授人以渔嘛(这句话是这么说的吧),顺便赚点应届学生MM的膜拜那就 ...

  3. 利用html 5 websocket做个山寨版web聊天室(手写C#服务器)

    在之前的博客中提到过看到html5 的websocket后很感兴趣,终于可以摆脱长轮询(websocket之前的实现方式可以看看Developer Works上的一篇文章,有简单提到,同时也说了web ...

  4. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(二) 之 ChatServer搭建,连接服务器,以及注意事项。

    上篇:ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(一) 之 基层数据搭建,让数据活起来(数据获取) 上一篇我们已经完成了初步界面的搭建工作,本篇将介绍IM的核心内容 ...

  5. 基于开源 Openfire 聊天服务器 - 开发Openfire聊天记录插件[转]

    上一篇文章介绍到怎么在自己的Java环境中搭建openfire插件开发的环境,同时介绍到怎样一步步简单的开发openfire插件.一步步很详细的介绍到简单插件开发,带Servlet的插件的开发.带JS ...

  6. openfire:基于开源 Openfire 聊天服务器 - 开发Openfire聊天记录插件

    基于开源 Openfire 聊天服务器 - 开发Openfire聊天记录插件 上一篇文章介绍到怎么在自己的Java环境中搭建openfire插件开发的环境,同时介绍到怎样一步步简单的开发openfir ...

  7. 基于开源 Openfire 聊天服务器 - 开发Openfire聊天记录插件

    原文:http://www.cnblogs.com/hoojo/archive/2013/03/29/openfire_plugin_chatlogs_plugin_.html 随笔-150  评论- ...

  8. 27.app后端搭建聊天服务器的经历

    现在,聊天功能已经成了社交app的标配了.但是,众多web开发出生的程序员对聊天相关的服务的不了解,带来了很多开发上的困扰.在这篇文章中,根据下面3个方面,谈谈聊天服务. 1.      聊天服务的技 ...

  9. Django小项目web聊天

    WEBQQ的实现的几种方式 1.HTTP协议特点 首先这里要知道HTTP协议的特点:短链接.无状态! 在不考虑本地缓存的情况举例来说:咱们在连接博客园的时候,当tcp连接后,我会把我自己的http头发 ...

  10. web聊天室

    开发一个web聊天室 功能需求: 1.用户可以与好友一对一聊天 2.群聊 所需知识 1.Django 2.bootstrap 3.CSS 4.ajax 涉及到的新的知识点 1.如果设计表结构的时候,一 ...

随机推荐

  1. Linux中ARP学习和老化机制

    本文分享自天翼云开发者社区<Linux中ARP学习和老化机制> 作者:云云生息 ARP学习和老化机制在Linux网络通信中起着至关重要的作用.ARP(Address Resolution ...

  2. SQL注入之布尔盲注

    SQL注入之布尔盲注 一.布尔盲注原理 布尔盲注是一种基于布尔逻辑的SQL注入攻击技术,其核心原理是通过构造特定的SQL查询语句,利用应用程序对查询结果的不同响应(通常是真或假)来逐步推断数据库中的信 ...

  3. 最长不降子序列 n log n 方案输出与 Dilworth 定理 - 动态规划模板

    朴素算法 不必多说,\(O(n^2)\) 的暴力 dp 转移. 优化算法 时间为 \(O(n \log n)\) ,本质是贪心,不是 dp . 思路是维护一个单调栈(手写版),使这个栈单调不降. 当该 ...

  4. SpringCloud自定义loadbalancer实现标签路由

    一.背景 最近前端反应开发环境有时候调接口会很慢,原因是有开发图方便将本地服务注册到开发环境,请求路由到开发本地导致, 为了解决该问题想到可以通过标签路由的方式避免该问题,实现前端联调和开发自测互不干 ...

  5. Thymeleaf select 反显 默认选中

    后台代码 List<ExamTestPaperDO> list = examTestPaperService.list(map); model.addAttribute("tes ...

  6. (自适应手机端)合同模板网站源码 合同范文类网站pbootcms模板

    PbootCMS内核开发的网站模板,该模板适用于合同范文网站.合同模板网站等企业,当然其他行业也可以做,只需要把文字图片换成其他行业的即可: pc+wap,同一个后台,数据即时同步,简单适用!附带测试 ...

  7. Zookeeper - 本地模式部署

    本地模式部署 zoo.cfg 参数解析 本地模式部署 1.上传zookeeper的安装包并解压 tar -zxvf zookeeper-x.x.x.tar.gz -c /xxx/xxx/ 2.将 zo ...

  8. Zookeeper、Hadoop、Hbase的启动顺序以及关闭顺序

    启动顺序 Hadoop及hbase集群启动顺序 zookeepeer -> hadoop -> hbase 停止顺序 Hadoop及hbase集群关闭顺序 hbase -> hado ...

  9. python面向对象-我敢站在世界巅峰保证:这里可以找到几乎百分之九十python面向对象的内容(面向对象三大特性、成员、组合、特殊成员、反射、类的约束、自定义异常、多继承之C3算法)

    概要: 面向对象 2 面向对象 Java语言:只支持面向对象方式 python语言: 面向过程[不推荐] 函数式[推荐] 面向对象[比较推荐]了解.能看懂.看源码 函数式编程:代码重用性.可读性较好 ...

  10. selenium 提示 Non-UTF-8 code starting with '\xc4'

    解决(1):在程序最上方加上语句,# coding=gbk 解决(2):在preference下进行修改