Browse Source

优化拉取离线消息效率

master
xsx 2 years ago
parent
commit
18725cfa17
  1. 6
      im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java
  2. 6
      im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java
  3. 2
      im-platform/src/main/resources/application.yml
  4. 134
      im-ui/src/store/chatStore.js
  5. 4
      im-ui/src/view/Home.vue

6
im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java

@ -159,14 +159,14 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
} }
// 开启加载中标志 // 开启加载中标志
this.sendLoadingMessage(true); this.sendLoadingMessage(true);
// 只能拉取最近1个月的,最多拉取1000条 // 只能拉取最近3个月的,最多拉取3000条
Date minDate = DateUtils.addMonths(new Date(), -1); Date minDate = DateUtils.addMonths(new Date(), -3);
LambdaQueryWrapper<GroupMessage> wrapper = Wrappers.lambdaQuery(); LambdaQueryWrapper<GroupMessage> wrapper = Wrappers.lambdaQuery();
wrapper.gt(GroupMessage::getId, minId) wrapper.gt(GroupMessage::getId, minId)
.gt(GroupMessage::getSendTime, minDate) .gt(GroupMessage::getSendTime, minDate)
.in(GroupMessage::getGroupId, groupIds) .in(GroupMessage::getGroupId, groupIds)
.ne(GroupMessage::getStatus, MessageStatus.RECALL.code()) .ne(GroupMessage::getStatus, MessageStatus.RECALL.code())
.orderByDesc(GroupMessage::getId).last("limit 1000"); .orderByDesc(GroupMessage::getId).last("limit 3000");
List<GroupMessage> messages = this.list(wrapper); List<GroupMessage> messages = this.list(wrapper);
// 通过群聊对消息进行分组 // 通过群聊对消息进行分组
Map<Long, List<GroupMessage>> messageGroupMap = messages.stream().collect(Collectors.groupingBy(GroupMessage::getGroupId)); Map<Long, List<GroupMessage>> messageGroupMap = messages.stream().collect(Collectors.groupingBy(GroupMessage::getGroupId));

6
im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java

@ -153,8 +153,8 @@ public class PrivateMessageServiceImpl extends ServiceImpl<PrivateMessageMapper,
List<Long> friendIds = friends.stream().map(Friend::getFriendId).collect(Collectors.toList()); List<Long> friendIds = friends.stream().map(Friend::getFriendId).collect(Collectors.toList());
// 获取当前用户的消息 // 获取当前用户的消息
LambdaQueryWrapper<PrivateMessage> queryWrapper = Wrappers.lambdaQuery(); LambdaQueryWrapper<PrivateMessage> queryWrapper = Wrappers.lambdaQuery();
// 只能拉取最近1个月的1000条消息 // 只能拉取最近3个月的3000条消息
Date minDate = DateUtils.addMonths(new Date(), -1); Date minDate = DateUtils.addMonths(new Date(), -3);
queryWrapper.gt(PrivateMessage::getId, minId) queryWrapper.gt(PrivateMessage::getId, minId)
.ge(PrivateMessage::getSendTime, minDate) .ge(PrivateMessage::getSendTime, minDate)
.ne(PrivateMessage::getStatus, MessageStatus.RECALL.code()) .ne(PrivateMessage::getStatus, MessageStatus.RECALL.code())
@ -164,7 +164,7 @@ public class PrivateMessageServiceImpl extends ServiceImpl<PrivateMessageMapper,
.or(wp -> wp.eq(PrivateMessage::getRecvId, session.getUserId()) .or(wp -> wp.eq(PrivateMessage::getRecvId, session.getUserId())
.in(PrivateMessage::getSendId, friendIds))) .in(PrivateMessage::getSendId, friendIds)))
.orderByDesc(PrivateMessage::getId) .orderByDesc(PrivateMessage::getId)
.last("limit 1000"); .last("limit 3000");
List<PrivateMessage> messages = this.list(queryWrapper); List<PrivateMessage> messages = this.list(queryWrapper);
// 消息顺序从小到大 // 消息顺序从小到大
CollectionUtil.reverse(messages); CollectionUtil.reverse(messages);

2
im-platform/src/main/resources/application.yml

@ -33,7 +33,7 @@ mybatis-plus:
minio: minio:
endpoint: http://127.0.0.1:9001 #内网地址 endpoint: http://127.0.0.1:9001 #内网地址
public: http://127.0.0.1:9001 #外网访问地址 public: http://192.168.2.67:9001 #外网访问地址
accessKey: admin accessKey: admin
secretKey: 12345678 secretKey: 12345678
bucketName: box-im bucketName: box-im

134
im-ui/src/store/chatStore.js

@ -2,8 +2,11 @@ import { MESSAGE_TYPE, MESSAGE_STATUS } from "../api/enums.js"
import userStore from './userStore'; import userStore from './userStore';
import localForage from 'localforage'; import localForage from 'localforage';
export default { /* 线cacheChats,
待所有离线消息拉取完成后再统一放至vuex中进行渲染*/
let cacheChats = [];
export default {
state: { state: {
activeChat: null, activeChat: null,
privateMsgMaxId: 0, privateMsgMaxId: 0,
@ -15,11 +18,12 @@ export default {
mutations: { mutations: {
initChats(state, chatsData) { initChats(state, chatsData) {
state.chats = chatsData.chats || []; state.chats = [];
state.privateMsgMaxId = chatsData.privateMsgMaxId || 0; state.privateMsgMaxId = chatsData.privateMsgMaxId || 0;
state.groupMsgMaxId = chatsData.groupMsgMaxId || 0; state.groupMsgMaxId = chatsData.groupMsgMaxId || 0;
cacheChats = chatsData.chats||[];
// 防止图片一直处在加载中状态 // 防止图片一直处在加载中状态
state.chats.forEach((chat) => { cacheChats.forEach((chat) => {
chat.messages.forEach((msg) => { chat.messages.forEach((msg) => {
if (msg.loadStatus == "loading") { if (msg.loadStatus == "loading") {
msg.loadStatus = "fail" msg.loadStatus = "fail"
@ -28,11 +32,12 @@ export default {
}) })
}, },
openChat(state, chatInfo) { openChat(state, chatInfo) {
let chats = this.getters.findChats()
let chat = null; let chat = null;
for (let idx in state.chats) { for (let idx in chats) {
if (state.chats[idx].type == chatInfo.type && if (chats[idx].type == chatInfo.type &&
state.chats[idx].targetId === chatInfo.targetId) { chats[idx].targetId === chatInfo.targetId) {
chat = state.chats[idx]; chat = chats[idx];
// 放置头部 // 放置头部
this.commit("moveTop", idx) this.commit("moveTop", idx)
break; break;
@ -52,28 +57,31 @@ export default {
atMe: false, atMe: false,
atAll: false atAll: false
}; };
state.chats.unshift(chat); chats.unshift(chat);
} }
}, },
activeChat(state, idx) { activeChat(state, idx) {
state.activeChat = state.chats[idx]; let chats = this.getters.findChats();
state.activeChat = chats[idx];
}, },
resetUnreadCount(state, chatInfo) { resetUnreadCount(state, chatInfo) {
for (let idx in state.chats) { let chats = this.getters.findChats();
if (state.chats[idx].type == chatInfo.type && for (let idx in chats) {
state.chats[idx].targetId == chatInfo.targetId) { if (chats[idx].type == chatInfo.type &&
state.chats[idx].unreadCount = 0; chats[idx].targetId == chatInfo.targetId) {
state.chats[idx].atMe = false; chats[idx].unreadCount = 0;
state.chats[idx].atAll = false; chats[idx].atMe = false;
chats[idx].atAll = false;
} }
} }
this.commit("saveToStorage"); this.commit("saveToStorage");
}, },
readedMessage(state, pos) { readedMessage(state, pos) {
for (let idx in state.chats) { let chats = this.getters.findChats();
if (state.chats[idx].type == 'PRIVATE' && for (let idx in chats) {
state.chats[idx].targetId == pos.friendId) { if (chats[idx].type == 'PRIVATE' &&
state.chats[idx].messages.forEach((m) => { chats[idx].targetId == pos.friendId) {
chats[idx].messages.forEach((m) => {
if (m.selfSend && m.status != MESSAGE_STATUS.RECALL) { if (m.selfSend && m.status != MESSAGE_STATUS.RECALL) {
// pos.maxId为空表示整个会话已读 // pos.maxId为空表示整个会话已读
if (!pos.maxId || m.id <= pos.maxId) { if (!pos.maxId || m.id <= pos.maxId) {
@ -87,28 +95,31 @@ export default {
this.commit("saveToStorage"); this.commit("saveToStorage");
}, },
removeChat(state, idx) { removeChat(state, idx) {
if (state.chats[idx] == state.activeChat) { let chats = this.getters.findChats();
if (chats[idx] == state.activeChat) {
state.activeChat = null; state.activeChat = null;
} }
state.chats.splice(idx, 1); chats.splice(idx, 1);
this.commit("saveToStorage"); this.commit("saveToStorage");
}, },
moveTop(state, idx) { moveTop(state, idx) {
// 加载中不移动,很耗性能 // 加载中不移动,很耗性能
if (state.loadingPrivateMsg || state.loadingGroupMsg) { if (this.getters.isLoading()) {
return; return;
} }
if (idx > 0) { if (idx > 0) {
let chat = state.chats[idx]; let chats = this.getters.findChats();
state.chats.splice(idx, 1); let chat = chats[idx];
state.chats.unshift(chat); chats.splice(idx, 1);
chats.unshift(chat);
this.commit("saveToStorage"); this.commit("saveToStorage");
} }
}, },
removePrivateChat(state, friendId) { removePrivateChat(state, friendId) {
for (let idx in state.chats) { let chats = this.getters.findChats();
if (state.chats[idx].type == 'PRIVATE' && for (let idx in chats) {
state.chats[idx].targetId == friendId) { if (chats[idx].type == 'PRIVATE' &&
chats[idx].targetId == friendId) {
this.commit("removeChat", idx); this.commit("removeChat", idx);
} }
} }
@ -218,8 +229,9 @@ export default {
this.commit("saveToStorage"); this.commit("saveToStorage");
}, },
updateChatFromFriend(state, friend) { updateChatFromFriend(state, friend) {
for (let i in state.chats) { let chats = this.getters.findChats();
let chat = state.chats[i]; for (let i in chats) {
let chat = chats[i];
if (chat.type == 'PRIVATE' && chat.targetId == friend.id) { if (chat.type == 'PRIVATE' && chat.targetId == friend.id) {
chat.headImage = friend.headImageThumb; chat.headImage = friend.headImageThumb;
chat.showName = friend.nickName; chat.showName = friend.nickName;
@ -229,8 +241,9 @@ export default {
this.commit("saveToStorage"); this.commit("saveToStorage");
}, },
updateChatFromGroup(state, group) { updateChatFromGroup(state, group) {
for (let i in state.chats) { let chats = this.getters.findChats();
let chat = state.chats[i]; for (let i in chats) {
let chat = chats[i];
if (chat.type == 'GROUP' && chat.targetId == group.id) { if (chat.type == 'GROUP' && chat.targetId == group.id) {
chat.headImage = group.headImageThumb; chat.headImage = group.headImageThumb;
chat.showName = group.showGroupName; chat.showName = group.showGroupName;
@ -239,23 +252,34 @@ export default {
} }
this.commit("saveToStorage"); this.commit("saveToStorage");
}, },
loadingPrivateMsg(state, loading) { loadingPrivateMsg(state, loading) {
state.loadingPrivateMsg = loading; state.loadingPrivateMsg = loading;
if (!state.loadingPrivateMsg && !state.loadingGroupMsg) { if (!this.getters.isLoading()) {
this.commit("sort") this.commit("refreshChats")
} }
}, },
loadingGroupMsg(state, loading) { loadingGroupMsg(state, loading) {
state.loadingGroupMsg = loading; state.loadingGroupMsg = loading;
if (!state.loadingPrivateMsg && !state.loadingGroupMsg) { if (!this.getters.isLoading()) {
this.commit("sort") this.commit("refreshChats")
} }
}, },
sort(state) { refreshChats(state) {
state.chats.sort((c1, c2) => c2.lastSendTime - c1.lastSendTime); // 排序
cacheChats.sort((chat1, chat2) => {
return chat2.lastSendTime - chat1.lastSendTime;
});
// 将消息一次性装载回来
state.chats = cacheChats;
// 断线重连后不能使用缓存模式,否则会导致聊天窗口的消息不刷新
cacheChats = state.chats;
this.commit("saveToStorage");
}, },
saveToStorage(state) { saveToStorage(state) {
// 加载中不保存,防止卡顿
if (this.getters.isLoading()) {
return;
}
let userId = userStore.state.userInfo.id; let userId = userStore.state.userInfo.id;
let key = "chats-" + userId; let key = "chats-" + userId;
let chatsData = { let chatsData = {
@ -266,8 +290,10 @@ export default {
localForage.setItem(key, chatsData) localForage.setItem(key, chatsData)
}, },
clear(state) { clear(state) {
state.activeChat = null; cacheChats = []
state.chats = []; state.chats = [];
state.activeChat = null;
} }
}, },
actions: { actions: {
@ -292,24 +318,32 @@ export default {
} }
}, },
getters: { getters: {
findChatIdx: (state) => (chat) => { isLoading: (state) => () => {
for (let idx in state.chats) { return state.loadingPrivateMsg || state.loadingGroupMsg
if (state.chats[idx].type == chat.type && },
state.chats[idx].targetId === chat.targetId) { findChats: (state, getters) => () => {
chat = state.chats[idx]; return getters.isLoading() ? cacheChats : state.chats;
},
findChatIdx: (state, getters) => (chat) => {
let chats = getters.findChats();
for (let idx in chats) {
if (chats[idx].type == chat.type &&
chats[idx].targetId === chat.targetId) {
chat = chats[idx];
return idx return idx
} }
} }
}, },
findChat: (state) => (msgInfo) => { findChat: (state, getters) => (msgInfo) => {
let chats = getters.findChats();
// 获取对方id或群id // 获取对方id或群id
let type = msgInfo.groupId ? 'GROUP' : 'PRIVATE'; let type = msgInfo.groupId ? 'GROUP' : 'PRIVATE';
let targetId = msgInfo.groupId ? msgInfo.groupId : msgInfo.selfSend ? msgInfo.recvId : msgInfo.sendId; let targetId = msgInfo.groupId ? msgInfo.groupId : msgInfo.selfSend ? msgInfo.recvId : msgInfo.sendId;
let chat = null; let chat = null;
for (let idx in state.chats) { for (let idx in chats) {
if (state.chats[idx].type == type && if (chats[idx].type == type &&
state.chats[idx].targetId === targetId) { chats[idx].targetId === targetId) {
chat = state.chats[idx]; chat = chats[idx];
break; break;
} }
} }

4
im-ui/src/view/Home.vue

@ -360,7 +360,7 @@
flex: 1; flex: 1;
.el-menu-item { .el-menu-item {
margin: 20px 0; margin: 25px 0;
background-color: #E8F2FF !important; background-color: #E8F2FF !important;
padding: 0 !important; padding: 0 !important;
text-align: center; text-align: center;
@ -376,7 +376,7 @@
.icon { .icon {
font-size: 26px; font-size: 26px;
color: black; color: #888;
} }
.unread-text { .unread-text {

Loading…
Cancel
Save