聊天存入數據庫需要的參數標識:
兩個用戶的標識
聊天消息內容
發送消息的時間
當前對話消息的標識
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
}
}