这是我参与「第五届青训营 」伴学笔记创作活动的第 13 天
这篇笔记是大项目的第五次总结,这次主要总结了对于定时轮询消息查询接口,获取最新消息列表的消息页面,如何完成消息页面的稳定获取。
直接返回messagesList
如果直接在后端将messagesList传输给前端,就会出现这种情况:刚点进消息页面的时候能正常显示消息,但由于前端页面定时轮询消息查询接口,后端的chat()函数被不断调用,messagesList被不断地传输至前端,就会导致消息列表一遍又一遍地重复呈现在前端。为了解决这种情况,需要有别的方法。
设置key为chatKey,value为消息记录的map
chatKey是用户A和用户B进行聊天时生成的一个key,这个key用于获取用户A和用户B的聊天记录,它定义如下:
func genChatKey(userIdA int64, userIdB int64) string {
if userIdA > userIdB {
return fmt.Sprintf("%d_%d", userIdB, userIdA)
}
return fmt.Sprintf("%d_%d", userIdA, userIdB)
}
每次调用chat函数时,检查用户A和B当前聊天记录的长度是否和map中记录的聊天记录长度相等,如果相等,则说明消息记录已经是最新的,不需要更新,可以传空集回前端;如果不相等,说明聊天记录有更新,需要传输最新的聊天记录集合给前端。最后,将最新的聊天记录更新至map中。为了完成这个方法,我写了个getNewMessages()函数,如下:
// 获得新的消息记录
func GetNewMessages(userIdA model.UserId, UserIdB model.UserId, newMessagesNums int) ([]model.Msg, error) {
if newMessagesNums <= 0 {
return []model.Msg{}, nil
}
res := make([]model.Msg, 0)
rows := make([]model.Msg, 0)
err := DB.Transaction(func(tx *gorm.DB) error {
err := tx.Debug().Table("messages").
Where("to_user_id IN (?) AND from_user_id IN (?)", []int64{userIdA, UserIdB}, []int64{userIdA, UserIdB}).
Order("create_time desc").
Limit(newMessagesNums).Find(&rows)
if err != nil {
return err.Error
}
return nil
})
//需要反着遍历数组,因为获得的后n个聊天记录是按时间倒叙排的,现在需要正着排
length := len(rows)
for i := length - 1; i >= 0; i-- {
row := rows[i]
if createTime_unix, err := TimeToUnix(row.CreateTime); err != nil {
return nil, err
} else {
//将带有Unix时间戳的结构体放入res中
r := model.Msg{
Id: row.Id,
ToUserId: row.ToUserId,
FromUserId: row.FromUserId,
Content: row.Content,
CreateTime: createTime_unix,
}
res = append(res, r)
}
}
return res, err
}
其中newMessagesNums就是需要更新的聊天记录条数。
chat函数如下编写:
chatKey := genChatKey(userId, int64(userIdB))
// 读取消息
messages, _ := dal.GetMessages(userId, int64(userIdB))
ChatLength := len(messages) //得到当前聊天的长度,如果长度没变就不更新
if _, mapExist := tempChat[chatKey]; mapExist {
//map存在时,说明已经写入过消息记录
newMessagesNums := ChatLength - len(tempChat[chatKey])
//获得最新的消息记录
if newMessages, err := dal.GetNewMessages(userId, int64(userIdB), newMessagesNums); err != nil {
return
} else {
finalMessages = newMessages
}
} else {
// map不存在
finalMessages = messages
}
//聊天记录长度存入map
//ChatKey_ChatLength[chatKey] = len(messages)
//聊天记录存入tempChat
tempChat[chatKey] = messages
//遍历finalMessages,就是最新更新的消息
for _, message := range finalMessages {
chatEvent := model.MessageSendEvent{
UserId: message.FromUserId,
ToUserId: message.ToUserId,
MsgContent: message.Content,
}
chatData, _ := json.Marshal(chatEvent)
_, err = conn.Write(chatData)
if err != nil {
fmt.Println("Error writing:", err.Error())
return
}
}
c.JSON(http.StatusOK, ChatResponse{Response: model.Response{StatusCode: 0}, MessageList: finalMessages})
这样就可以防止定时轮询消息查询接口中重复出现消息记录的问题。
此外,由于退出消息页面再进来时map并没有清空,所以会出现没有不显示消息记录的问题,这里可以通过检测用户在离开时,消息服务器断开,同时清空map中对应的聊天记录解决。
以上就是我对如何完成消息页面的稳定获取的总结。