聊天存入数据库需要的参数标识:
两个用户的标识
聊天消息内容
发送消息的时间
当前对话消息的标识
1、在前台的异步请求中,使用socket来发送消息
向后台发送时,应该将两个用户的标识传递,且能看出谁向谁发,还要携带聊天内容
2、在后台中,使用socket来接收,不需要路由组件,写成外部模块来接收
后台收取到后存入数据库中,并向客户端返回存入的内容
其中:因为客户端都是监听的相同名称,所以都能收到服务器返回的发送内容
3、在用户登录等时候,就向后台发送请求,获取消息列表
通过当前对话消息的标识,确定当前对话的消息
通过用户的标识,确定谁发送
通过消息的时间标识,确定谁先发送
4、实时同步每条消息
消息发送后,后台接收存入数据库然后将发送的消息发挥前端,前端监听接收后,将触发方法使得消息列表增加该消息,如reducer中增加一个case,来使得消息列表增加
基于React的Redux模式下的代码示例:
actions.js中异步方法使用socketio发送:
function initIO(dispatch,userid)
{
if(!io.socket){
io.socket=io('ws://localhost:4000')
io.socket.on('receiveMsg', function (chatMsg) {
console.log('浏览器端接收到消息:', chatMsg)
//只有当前会话才分发action保存
if(userid==chatMsg.from||userid==chatMsg.to)
{
dispatch(receiveMsg(chatMsg))
}
})
}
}
//异步发送消息
export const sendMsg=({from,to,content})=>{
return dispatch=>{
initIO();
console.log('浏览器发送消息',{from,to,content})
io.socket.emit('sendMsg',{from,to,content})
}
}
后台:
let express = require('express')
var bodyParser = require('body-parser');
var md5=require('blueimp-md5');
var cookieParser = require('cookie-parser');
var urlencodedParser = bodyParser.urlencoded({ extended: false });
const {UserModel,ChatModel} =require('./db/models');
const filter={password:0,__v:0};
var app=express();
//socket.io
var server = require('http').Server(app);
require('./socketio/test')(server);
server.listen(4000,function(){
console.log('this express server is running at http://127.0.0.1:4000 ');
});
app.use(cookieParser());
...
引入的模块:
const {ChatModel}=require('../db/models')
module.exports = function (server) {
// 得到 IO 对象
const io = require('socket.io')(server)
//监视连接(当有一个客户连接上时回调)
io.on('connection', function (socket) {
console.log('soketio connected')
// 绑定 sendMsg 监听, 接收客户端发送的消息
socket.on('sendMsg', function ({from,to,content}) {
console.log('服务器接收客户端发送',{from,to,content})
//保存消息进数据库,再将保存信息返回给前台
const chat_id=[from,to].sort().join('-');
const create_time=Date.now();
//存入数据库
new ChatModel({from,to,content,chat_id,create_time}).save(function(err,chatMsg){
//向客户端发送数据
io.emit('receiveMsg',chatMsg);
})
})
})
}
获取消息列表:
//异步获取消息函数
async function getMsgList(dispatch,userid)
{
initIO(dispatch,userid);
const response =await reqChatMsgList();
const res=response.data
if(res.code===0)
{
const{users,chatMsgs}=res.data
dispatch(receiveMsgList({users,chatMsgs}))
}
}
前台获取到消息后,根据标识对消息的处理:
const {user}=this.props
const {users,chatMsgs}=this.props.chat
//计算当前聊天的chatId
const meId=user._id;
if(!users[meId])
{
return null;
}
const targetId=this.props.match.params.userid;
const chatId=[meId,targetId].sort().join('-');
//获取当前对话的所有消息
const msgs=chatMsgs.filter(msg=>msg.chat_id==chatId)
//头像
const targetHeader=users[targetId].header;
const targetIcon=require(`../../assets/imgs/${targetHeader}.png`)
return
{
msgs.map(msg=>{
if(meId===msg.to) //对方发给我的
{
return <Item
key={msg._id}
thumb={targetIcon}
>
{msg.content}
</Item>
}else{
return <Item
key={msg._id}
className='chat-me'
extra='我'
>
{msg.content}
</Item>
}
})
}
reducer:
//聊天状态
const initChat={
users:{},
chatMsgs:[],
unReadCount:0 //总未读数量
}
function chat(state=initChat,action)
{
switch(action.type)
{
case RECEIVE_MSG_LIST:
const {users,chatMsgs}=action.data
return {
users,
chatMsgs,
unReadCount:0
}
case RECEIVE_MSG:
const chatMsg=action.data
return {
users:state.users,
chatMsgs:[...state.chatMsgs,chatMsg],
unReadCount:0
}
default:
return state
}
}