私信还是挺复杂的
首先是发送:
前端点击发送私信,传私信内容,私信对象和私信时间到后端。后端比较复杂,因为不光写进自己的私信表还要写进对方的私信表,这时候就体现出数据库设计的重要性了。这里是边看数据库边写的,也发现了一些设计的问题(比如一开始没有加时间字段会导致后期将私信渲染出来的时候不知道谁先发谁后发,还有name字段,不加的话后面渲染也不知道这是谁发的),同时改。
最后的数据库格式:
/*我的私信*/
"message":[
{
"with":String,//nickName
"myMessageContent":[ //我发送的多条私信
{
"name":String,
"sendTime":Date,//根据时间排列渲染
"content":String
}
],
"hisMessageContent":[ //对方发送的多条私信
{
"name":String,
"sendTime":Date,
"content":String
}
]
}
],
先理解一下这个数组集合吧,这个数组里有多个对象,每个对象我称为一个对话,with是对话的对象,myMessageContent这个数组里放的是我发送的每一条信息,这里name其实固定都是‘我’,方便后期渲染,sendTime是发送时间,也是便于后面在私信页根据各个私信的发送时间进行渲染(后面要将两个数组结合起来判断时间先后),content就是发送的内容了,同理,hisMessageContent里就是对方发送的每一条信息,name就是对方的nickName
后端的大概逻辑是这样的,前端传参数过来,两个用户表都要插数据,用户表和要发送对象的表。
用户表逻辑是:首先查找是否有与发送对象信息的数组数据(也就是with这一项),如果没有插入新的一项数组(写with和myMessageContent里面的内容),如果有在那个数组里插入myMessageContent这一项。
对方表逻辑也差不多,只是把数据写在hisMessageContent里,具体看代码。(这里mongoose插入二维数组有点懵,写法是在条件查询后的第二个变量里写message.$.myMessageContent插入,关键是这个$要注意,也不太懂是啥意思,反正这么写就能插二维数组)
//私信功能
router.post("/message", (req,res,next) => {
var errFlag = false;
var userId = req.session.user.userId;
var userNickName = req.session.user.userNickName;
var sendTo = req.body.toWhom;
var messageContent = req.body.messageContent;
var messageSendTime = req.body.time;
//自己无法发送私信给自己
if(req.session.user.userNickName == sendTo){
res.json({
status:'2',
msg:'自己不可以发送自己'
})
}else{
//在我的视角下发送给对方,写入自己的对话表
User.findOne({'userId':userId,'message.with':sendTo},(err,doc)=>{
if(doc==null){//如果之前没有和这个用户进行过对话,则插入一条新会话
User.update({'userId':userId},{
$push:{
'message':{
with:sendTo,
myMessageContent:{
name:'我',
sendTime:messageSendTime,
content:messageContent
}
}
}
},(err,doc)=>{
if(err)errFlag=true
console.log('suc1')
})
}else{//如果已经有了和这个用户的会话,直接插入会话信息
User.update({'userId':userId,'message.with':sendTo},{
$push:{
"message.$.myMessageContent":{
name:'我',
sendTime:messageSendTime,
content:messageContent
}
}
},(err,doc)=>{
if(err)errFlag=true
console.log("suc2")
})
}
})
//对方的视角下接收,写入对方的对话表
User.findOne({'userNickName':sendTo,'message.with':userNickName},(err,doc)=>{
if(doc==null){//如果之前没有和这个用户进行过对话,则插入一条新会话
User.update({'userNickName':sendTo},{
$push:{
'message':{
with:userNickName,
hisMessageContent:{
name:userNickName,
sendTime:messageSendTime,
content:messageContent
}
}
}
},(err,doc)=>{
if(err)errFlag=true
console.log("suc3")
})
}else{//如果已经有了和这个用户的会话,直接插入会话信息
User.update({'userNickName':sendTo,'message.with':userNickName},{
$push:{
"message.$.hisMessageContent":{
name:userNickName,
sendTime:messageSendTime,
content:messageContent
}
}
},(err,doc)=>{
if(err)errFlag=true
console.log("suc4")
})
}
})
if(errFlag){
res.json({
status:'1',
msg:'err'
})
}else{
res.json({
status:'0',
msg:'suc'
})
}
}
})
私信写进数据库了,接下来是在私信页和私信详情页将它们渲染出来。
首先是私信页,私信页主要是将用户对话渲染出来。渲染所有对话,然后按最新消息显示出来,这个逻辑主要在后端做的。
逻辑:前端不需要传参数到后端,后端根据用户的session直接拿到他的message数据,然后将他的message里的自己与收到的消息数据数组合并,根据时间进行排序,返回给前端最新的一条消息(这是单个对话的最新消息),形如[{who:xxx,toWhom:xxx,message:xxx,time:xxx}],最后还需要将整个数组根据时间排序返回最新的对话(这是所有对话全部进行排列得到的最新消息),前端根据这些信息进行渲染。看代码:
//获取自己的私信会话列表
router.get("/getMessageDialog", (req,res,next) => {
var userId = req.session.user.userId;
User.findOne({'userId':userId},{'message':1},(err,doc)=>{
if(err){
res.json({
status:'1',
msg:'err'
})
}else{
var array=[];
var linkArray=[];
var value;
//返回形如[{who:xxx,toWhom:xxx,message:xxx,time:xxx}]
for(var i=0;i<doc.message.length;i++){
linkArray = doc.message[i].myMessageContent.concat(doc.message[i].hisMessageContent)
for(var k=0;k<linkArray.length;k++){
for(var j=i+1;j<linkArray.length;j++){
if(linkArray[k].sendTime<linkArray[j].sendTime){
value=linkArray[j];
linkArray[j]=linkArray[k];
linkArray[k]=value;
}
}
}
if(linkArray[0].name=='我')
array[i]={who:'我',toWhom:doc.message[i].with,message:linkArray[0].content,time:linkArray[0].sendTime}
else
array[i]={who:doc.message[i].with,toWhom:'我',message:linkArray[0].content,time:linkArray[0].sendTime}
}
//全部对话根据最新消息返回
for(var i=0;i<array.length;i++){
for(var j=i+1;j<array.length;j++){
if(array[i].time<array[j].time){
value=array[j];
array[j]=array[i];
array[i]=value;
}
}
}
res.json({
status:'0',
msg:array
})
}
})
})
ok,私信详情页
私信详情和私信页差不多,还要简单许多,也是将自己的消息和对方的消息集合在一个数组按时间进行排列返回,前端渲染。
//获取与xxx的私信内容功能 返回按时间排列顺序的message内容
router.post("/getMessage", (req,res,next) => {
User.findOne({'userId':req.session.user.userId,'message.with':req.body.withWhom},{'message.$':1},(err,doc)=>{
if(err){
res.json({
status:'1',
msg:err.message
})
}else{
var linkArray = doc.message[0].myMessageContent.concat(doc.message[0].hisMessageContent)//把这个数组按sendTime时间进行排序重组返回前端
var value;
for(var i=0;i<linkArray.length;i++){
for(var j=i+1;j<linkArray.length;j++){
if(linkArray[i].sendTime<linkArray[j].sendTime){
value=linkArray[j];
linkArray[j]=linkArray[i];
linkArray[i]=value;
}
}
}
res.json({
status:'0',
msg:linkArray
})
}
})
})
至此私信功能就结束了。