一个实时聊天的功能,其核心就是websokect,进行双向平等对话,从后端主动推送消息到前端,实现实时推送消息的功能。
(需在Web端获取账号)
我们要实现一个实时聊天功能,包括单聊和群聊,避免无差别的广播,需支持向指定用户发送消息。
还需要区分在线和离线状态,因此聊天信息必须存储到MySQL数据库,这样即使用户离线,重新上线时也能收到未读消息。
实时聊天的核心是WebSocket,它支持双向通信,后端可以主动向前端推送消息。关于WebSocket的具体介绍,可以查看以下链接:
接下来,编写后端核心代码,这里使用Node.js的Express框架。
如果想用Java作为后端,可以参考这个帖子:Springboot实现WebSocket
代码解析:conn
是用户连接信息,用户连接到WebSocket时,会将其ID发送给后端并以ID作为key存储连接信息,以实现单聊或指定群聊功能,broadcast()
则用于发送指定用户的消息。
let conns2 = {}; // 实时聊天用户连接属性集
// websocket 实时聊天
const wss2 = new WebSocket.Server({ port: 8082 });
wss2.on('connection', function connection(ws, req) {
// 获取用户ID
let index = req.url.indexOf('=');
let id = req.url.substr(index + 1, req.url.length);
console.log('成功连接实时聊天, 用户: ' + id);
conns2[id] = ws; // 存储用户连接信息
ws.on('message', function incoming(message) {
const obj = JSON.parse(message);
broadcast(obj); // 广播消息
});
ws.on('close', function(e) {
console.log(e, '服务端连接关闭');
});
ws.on('error', function(e) {
console.log(e, '服务端异常');
});
});
在broadcast
函数中,我们判断消息的类型,确认是单聊还是群聊,并将消息发送给在线的用户。
// 实时聊天发送消息处理
function broadcast(obj) {
let users = [];
if (obj.type === '1') { // 单聊
users.push(obj.send_id);
users.push(obj.accept_id);
} else if (obj.type === '2') { // 群聊
users = obj.accept_group;
}
if (users && users.length) {
users.forEach(item => {
if (typeof conns2[item] === 'undefined') {
console.log(item + '---该用户已离线');
} else {
conns2[item].send(JSON.stringify(obj)); // 发送消息
}
});
}
}
接下来,编写前端样式,这里使用Vue框架。
<template>
<div class="mess">
<div class="mess_user_list">
<div class="user">
<el-avatar :size="40" :src="userAvatar" style="margin: 5px;"></el-avatar>
{{userName}}
</div>
<div class="user_list">
<div v-for="(item, index) in userList" :key="index" @click="showmessdlog(item)" class="user_list_item">
<el-avatar :size="40" :src="userAvatar" style="margin: 5px;"></el-avatar>
<div>
{{item.name}}
[{{messlst[item.id][messlst[item.id].length-1].send_name}}] {{messlst[item.id][messlst[item.id].length-1].content}}
暂无消息
</div>
</div>
</div>
</div>
<div v-if="acceptUser !== ''" class="mess_dialog">
<div class="dlog_header">{{acceptUser}}</div>
<div class="dlog_content">
<div v-for="(item, index) in messnowList" :key="index" class="dlog_content_item" style="margin-left: 5px;">
<div v-if="item.send_id !== userId" class="content_other">
{{item.send_name}} {{item.send_date}}
{{item.content}}
</div>
<div v-else class="content_me">
{{item.send_date}} {{item.send_name}}
{{item.content}}
</div>
</div>
</div>
<div class="dlog_footer">
<el-input type="textarea" :rows="5" v-model="mess"></el-input>
<el-button type="primary" @click="Wssendmess" style="float: right; margin-top: 5px;">发送</el-button>
</div>
</div>
<div v-else class="mess_dialog_false">
暂无消息,请选择用户对象
</div>
</div>
</template>
CSS样式如下:
<style scoped>
.mess {
border-radius: 5px;
margin: 20px auto;
width: 950px;
height: 600px;
border: 1px #8a8282;
box-shadow: 0 0 10px #9b9393;
background-color: white;
display: flex;
}
.mess_user_list {
width: 270px;
height: 100%;
background-color: #9f9c9c;
}
.mess_dialog {
width: 680px;
height: 600px;
}
.mess_dialog_false {
width: 680px;
height: 600px;
text-align: center;
line-height: 600px;
}
.dlog_header, .user {
height: 60px;
display: flex;
align-items: center;
border-bottom: 1px solid #0a0a0a;
}
.user_list {
height: 540px;
overflow-y: scroll;
}
.user_list_item {
height: 60px;
background-color: #b3b3b4;
display: flex;
align-items: center;
}
.content_other {
width: 650px;
}
.content_me {
width: 650px;
text-align: right;
}
</style>
最后,编写前端JavaScript代码,连接后端WebSocket并监听状态变化,绑定事件处理:
const ws = new WebSocket('ws://localhost:8082?id=' + id);
mounted() {
ws.addEventListener('open', this.handleWsOpen.bind(this), false);
ws.addEventListener('close', this.handleWsClose.bind(this), false);
ws.addEventListener('error', this.handleWsError.bind(this), false);
ws.addEventListener('message', this.handleWsMessage.bind(this), false);
},
methods: {
handleWsOpen() {
console.log('WebSocket已打开');
},
handleWsClose(e) {
console.log('WebSocket连接关闭:', e);
},
handleWsError(e) {
console.log('WebSocket发生错误:', e);
},
handleWsMessage(e) {
console.log('WebSocket收到消息:', e.data);
}
}
连接成功后,前端可以使用ws.send()
发送消息给后端,同时存储在MySQL中,后端会处理后按需给对应的前端发送消息。
原文地址:CSDN博客
本站主要用于日常笔记的记录和生活日志。本站不保证所有内容信息可靠!(大多数文章属于搬运!)如有版权问题,请联系我立即删除:“abcdsjx@126.com”。
QQ: 1164453243
邮箱: abcdsjx@126.com