Browse Source

ws重连优化

master
xie.bx 2 years ago
parent
commit
5dedc178b1
  1. 24
      im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java
  2. 33
      im-ui/src/api/wssocket.js
  3. 5
      im-ui/src/components/chat/ChatBox.vue
  4. 63
      im-ui/src/view/Home.vue
  5. 19
      im-uniapp/App.vue
  6. 38
      im-uniapp/common/wssocket.js

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

@ -1,8 +1,10 @@
package com.bx.implatform.service.impl; package com.bx.implatform.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bx.imclient.IMClient; import com.bx.imclient.IMClient;
@ -198,6 +200,9 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
UserSession session = SessionContext.getSession(); UserSession session = SessionContext.getSession();
List<GroupMember> members = groupMemberService.findByUserId(session.getUserId()); List<GroupMember> members = groupMemberService.findByUserId(session.getUserId());
List<Long> ids = members.stream().map(GroupMember::getGroupId).collect(Collectors.toList()); List<Long> ids = members.stream().map(GroupMember::getGroupId).collect(Collectors.toList());
if(CollectionUtil.isEmpty(ids)){
return Collections.EMPTY_LIST;
}
// 只能拉取最近1个月的 // 只能拉取最近1个月的
Date minDate = DateTimeUtils.addMonths(new Date(), -1); Date minDate = DateTimeUtils.addMonths(new Date(), -1);
LambdaQueryWrapper<GroupMessage> wrapper = Wrappers.lambdaQuery(); LambdaQueryWrapper<GroupMessage> wrapper = Wrappers.lambdaQuery();
@ -242,6 +247,16 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
@Override @Override
public void readedMessage(Long groupId) { public void readedMessage(Long groupId) {
UserSession session = SessionContext.getSession(); UserSession session = SessionContext.getSession();
// 取出最后的消息id
LambdaQueryWrapper<GroupMessage> wrapper = Wrappers.lambdaQuery();
wrapper.eq(GroupMessage::getGroupId, groupId)
.orderByDesc(GroupMessage::getId)
.last("limit 1")
.select(GroupMessage::getId);
GroupMessage message = this.getOne(wrapper);
if(Objects.isNull(message)){
return;
}
// 推送消息给自己的其他终端 // 推送消息给自己的其他终端
GroupMessageVO msgInfo = new GroupMessageVO(); GroupMessageVO msgInfo = new GroupMessageVO();
msgInfo.setType(MessageType.READED.code()); msgInfo.setType(MessageType.READED.code());
@ -254,14 +269,7 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
sendMessage.setData(msgInfo); sendMessage.setData(msgInfo);
sendMessage.setSendResult(false); sendMessage.setSendResult(false);
imClient.sendGroupMessage(sendMessage); imClient.sendGroupMessage(sendMessage);
// 记录已读消息位置
// 记录已读位置
LambdaQueryWrapper<GroupMessage> wrapper = Wrappers.lambdaQuery();
wrapper.eq(GroupMessage::getGroupId, groupId)
.orderByDesc(GroupMessage::getId)
.last("limit 1")
.select(GroupMessage::getId);
GroupMessage message = this.getOne(wrapper);
String key = StrUtil.join(":",RedisKey.IM_GROUP_READED_POSITION,groupId,session.getUserId()); String key = StrUtil.join(":",RedisKey.IM_GROUP_READED_POSITION,groupId,session.getUserId());
redisTemplate.opsForValue().set(key, message.getId()); redisTemplate.opsForValue().set(key, message.getId());

33
im-ui/src/api/wssocket.js

@ -1,19 +1,11 @@
var websock = null; var websock = null;
let rec; //断线重连后,延迟5秒重新创建WebSocket连接 rec用来存储延迟请求的代码 let rec; //断线重连后,延迟5秒重新创建WebSocket连接 rec用来存储延迟请求的代码
let isConnect = false; //连接标识 避免重复连接 let isConnect = false; //连接标识 避免重复连接
let wsurl = "";
let accessToken = "";
let messageCallBack = null; let messageCallBack = null;
let openCallBack = null;
let closeCallBack = null let closeCallBack = null
let init = (url,token) => { let connect = (wsurl,accessToken) => {
wsurl = url;
accessToken = token;
};
let connect = () => {
try { try {
if (isConnect) { if (isConnect) {
return; return;
@ -25,8 +17,6 @@ let connect = () => {
if (sendInfo.cmd == 0) { if (sendInfo.cmd == 0) {
heartCheck.start() heartCheck.start()
console.log('WebSocket登录成功') console.log('WebSocket登录成功')
// 登录成功才算连接完成
openCallBack && openCallBack();
} else if (sendInfo.cmd == 1) { } else if (sendInfo.cmd == 1) {
// 重新开启心跳定时 // 重新开启心跳定时
heartCheck.reset(); heartCheck.reset();
@ -59,16 +49,16 @@ let connect = () => {
websock.onerror = function() { websock.onerror = function() {
console.log('WebSocket连接发生错误') console.log('WebSocket连接发生错误')
isConnect = false; //连接断开修改标识 isConnect = false; //连接断开修改标识
reConnect(); reconnect(wsurl,accessToken);
} }
} catch (e) { } catch (e) {
console.log("尝试创建连接失败"); console.log("尝试创建连接失败");
reConnect(); //如果无法连接上webSocket 那么重新连接!可能会因为服务器重新部署,或者短暂断网等导致无法创建连接 reconnect(wsurl,accessToken); //如果无法连接上webSocket 那么重新连接!可能会因为服务器重新部署,或者短暂断网等导致无法创建连接
} }
}; };
//定义重连函数 //定义重连函数
let reConnect = () => { let reconnect = (wsurl,accessToken) => {
console.log("尝试重新连接"); console.log("尝试重新连接");
if (isConnect){ if (isConnect){
//如果已经连上就不在重连了 //如果已经连上就不在重连了
@ -76,12 +66,12 @@ let reConnect = () => {
} }
rec && clearTimeout(rec); rec && clearTimeout(rec);
rec = setTimeout(function() { // 延迟5秒重连 避免过多次过频繁请求重连 rec = setTimeout(function() { // 延迟5秒重连 避免过多次过频繁请求重连
connect(); connect(wsurl,accessToken);
}, 5000); }, 15000);
}; };
//设置关闭连接 //设置关闭连接
let close = () => { let close = (code) => {
websock && websock.close(); websock && websock.close(code);
}; };
@ -136,20 +126,15 @@ let onMessage = (callback) => {
} }
let onOpen = (callback) => {
openCallBack = callback;
}
let onClose = (callback) => { let onClose = (callback) => {
closeCallBack = callback; closeCallBack = callback;
} }
// 将方法暴露出去 // 将方法暴露出去
export { export {
init,
connect, connect,
reconnect,
close, close,
sendMessage, sendMessage,
onOpen,
onMessage, onMessage,
onClose onClose
} }

5
im-ui/src/components/chat/ChatBox.vue

@ -512,11 +512,13 @@
// //
this.scrollToBottom(); this.scrollToBottom();
this.sendText = ""; this.sendText = "";
this.showSide = false;
// //
this.readedMessage() this.readedMessage()
// 30 // 30
let size = this.chat.messages.length; let size = this.chat.messages.length;
this.showMinIdx = size > 30 ? size - 30 : 0; this.showMinIdx = size > 30 ? size - 30 : 0;
// //
this.$nextTick(() => { this.$nextTick(() => {
this.$refs.sendBox.focus(); this.$refs.sendBox.focus();
@ -573,7 +575,7 @@
.im-chat-box { .im-chat-box {
>ul { >ul {
padding: 20px; padding: 0 20px;
li { li {
list-style-type: none; list-style-type: none;
@ -612,6 +614,7 @@
} }
.send-content-area { .send-content-area {
position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;

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

@ -74,7 +74,7 @@
data() { data() {
return { return {
showSettingDialog: false, showSettingDialog: false,
lastPlayAudioTime: new Date()-1000 lastPlayAudioTime: new Date() - 1000
} }
}, },
methods: { methods: {
@ -84,16 +84,19 @@
this.loadPrivateMessage(this.$store.state.chatStore.privateMsgMaxId); this.loadPrivateMessage(this.$store.state.chatStore.privateMsgMaxId);
this.loadGroupMessage(this.$store.state.chatStore.groupMsgMaxId); this.loadGroupMessage(this.$store.state.chatStore.groupMsgMaxId);
// ws // ws
this.$wsApi.init(process.env.VUE_APP_WS_URL, sessionStorage.getItem("accessToken")); this.$wsApi.connect(process.env.VUE_APP_WS_URL, sessionStorage.getItem("accessToken"));
this.$wsApi.connect();
this.$wsApi.onOpen();
this.$wsApi.onMessage((cmd, msgInfo) => { this.$wsApi.onMessage((cmd, msgInfo) => {
if (cmd == 2) { if (cmd == 2) {
// ws
this.$wsApi.close(3000)
// 线 // 线
this.$message.error("您已在其他地方登陆,将被强制下线"); this.$alert("您已在其他地方登陆,将被强制下线", "强制下线通知", {
setTimeout(() => { confirmButtonText: '确定',
location.href = "/"; callback: action => {
}, 1000) location.href = "/";
}
});
} else if (cmd == 3) { } else if (cmd == 3) {
// //
this.handlePrivateMessage(msgInfo); this.handlePrivateMessage(msgInfo);
@ -104,20 +107,18 @@
}) })
this.$wsApi.onClose((e) => { this.$wsApi.onClose((e) => {
console.log(e); console.log(e);
if (e.code == 1006) { if (e.code != 3000) {
// // 线
this.$message.error("连接已断开,请重新登录"); this.$message.error("连接断开,正在尝试重新连接...");
location.href = "/"; this.$wsApi.reconnect(process.env.VUE_APP_WS_URL, sessionStorage.getItem("accessToken"));
} else {
this.$wsApi.connect();
} }
}); });
}).catch((e) => { }).catch((e) => {
console.log("初始化失败",e); console.log("初始化失败", e);
}) })
}, },
loadPrivateMessage(minId) { loadPrivateMessage(minId) {
this.$store.commit("loadingPrivateMsg",true) this.$store.commit("loadingPrivateMsg", true)
this.$http({ this.$http({
url: "/message/private/loadMessage?minId=" + minId, url: "/message/private/loadMessage?minId=" + minId,
method: 'get' method: 'get'
@ -126,20 +127,20 @@
msgInfo.selfSend = msgInfo.sendId == this.$store.state.userStore.userInfo.id; msgInfo.selfSend = msgInfo.sendId == this.$store.state.userStore.userInfo.id;
let friendId = msgInfo.selfSend ? msgInfo.recvId : msgInfo.sendId; let friendId = msgInfo.selfSend ? msgInfo.recvId : msgInfo.sendId;
let friend = this.$store.state.friendStore.friends.find((f) => f.id == friendId); let friend = this.$store.state.friendStore.friends.find((f) => f.id == friendId);
if(friend){ if (friend) {
this.insertPrivateMessage(friend,msgInfo); this.insertPrivateMessage(friend, msgInfo);
} }
}) })
if (msgInfos.length == 100) { if (msgInfos.length == 100) {
// //
this.loadPrivateMessage(msgInfos[99].id); this.loadPrivateMessage(msgInfos[99].id);
}else{ } else {
this.$store.commit("loadingPrivateMsg",false) this.$store.commit("loadingPrivateMsg", false)
} }
}) })
}, },
loadGroupMessage(minId) { loadGroupMessage(minId) {
this.$store.commit("loadingGroupMsg",true) this.$store.commit("loadingGroupMsg", true)
this.$http({ this.$http({
url: "/message/group/loadMessage?minId=" + minId, url: "/message/group/loadMessage?minId=" + minId,
method: 'get' method: 'get'
@ -148,15 +149,15 @@
msgInfo.selfSend = msgInfo.sendId == this.$store.state.userStore.userInfo.id; msgInfo.selfSend = msgInfo.sendId == this.$store.state.userStore.userInfo.id;
let groupId = msgInfo.groupId; let groupId = msgInfo.groupId;
let group = this.$store.state.groupStore.groups.find((g) => g.id == groupId); let group = this.$store.state.groupStore.groups.find((g) => g.id == groupId);
if(group){ if (group) {
this.insertGroupMessage(group,msgInfo); this.insertGroupMessage(group, msgInfo);
} }
}) })
if (msgInfos.length == 100) { if (msgInfos.length == 100) {
// //
this.loadGroupMessage(msgInfos[99].id); this.loadGroupMessage(msgInfos[99].id);
}else{ } else {
this.$store.commit("loadingGroupMsg",false) this.$store.commit("loadingGroupMsg", false)
} }
}) })
}, },
@ -212,7 +213,7 @@
// //
this.$store.commit("insertMessage", msg); this.$store.commit("insertMessage", msg);
// //
if(!msg.selfSend && msg.status != this.$enums.MESSAGE_STATUS.READED){ if (!msg.selfSend && msg.status != this.$enums.MESSAGE_STATUS.READED) {
this.playAudioTip(); this.playAudioTip();
} }
}, },
@ -247,7 +248,7 @@
// //
this.$store.commit("insertMessage", msg); this.$store.commit("insertMessage", msg);
// //
if(!msg.selfSend && msg.status != this.$enums.MESSAGE_STATUS.READED){ if (!msg.selfSend && msg.status != this.$enums.MESSAGE_STATUS.READED) {
this.playAudioTip(); this.playAudioTip();
} }
}, },
@ -257,14 +258,14 @@
location.href = "/"; location.href = "/";
}, },
playAudioTip() { playAudioTip() {
if(new Date() - this.lastPlayAudioTime > 1000){ if (new Date() - this.lastPlayAudioTime > 1000) {
this.lastPlayAudioTime = new Date(); this.lastPlayAudioTime = new Date();
let audio = new Audio(); let audio = new Audio();
let url = require(`@/assets/audio/tip.wav`); let url = require(`@/assets/audio/tip.wav`);
audio.src = url; audio.src = url;
audio.play(); audio.play();
} }
}, },
showSetting() { showSetting() {
this.showSettingDialog = true; this.showSettingDialog = true;

19
im-uniapp/App.vue

@ -28,10 +28,8 @@
}, },
initWebSocket() { initWebSocket() {
let loginInfo = uni.getStorageSync("loginInfo") let loginInfo = uni.getStorageSync("loginInfo")
let userId = store.state.userStore.userInfo.id; wsApi.init();
wsApi.init(process.env.WS_URL, loginInfo.accessToken); wsApi.connect(process.env.WS_URL, loginInfo.accessToken);
wsApi.connect();
wsApi.onOpen()
wsApi.onMessage((cmd, msgInfo) => { wsApi.onMessage((cmd, msgInfo) => {
if (cmd == 2) { if (cmd == 2) {
// 线 // 线
@ -49,20 +47,15 @@
} }
}); });
wsApi.onClose((res) => { wsApi.onClose((res) => {
// 10063000APP // 3000
if (res.code == 1006) { if (res.code != 3000) {
uni.showToast({
title: '连接已断开,请重新登录',
icon: 'none',
})
this.exit();
} else if (res.code != 3000) {
// //
uni.showToast({ uni.showToast({
title: '连接已断开,尝试重新连接...', title: '连接已断开,尝试重新连接...',
icon: 'none', icon: 'none',
}) })
wsApi.connect(); let loginInfo = uni.getStorageSync("loginInfo")
wsApi.reconnect(process.env.WS_URL, loginInfo.accessToken);
} }
}) })
}, },

38
im-uniapp/common/wssocket.js

@ -1,20 +1,12 @@
let wsurl = ""; let wsurl = "";
let accessToken = ""; let accessToken = "";
let openCallBack = null;
let messageCallBack = null; let messageCallBack = null;
let closeCallBack = null; let closeCallBack = null;
let isConnect = false; //连接标识 避免重复连接 let isConnect = false; //连接标识 避免重复连接
let hasInit = false; let rec = null;
let init = () => {
let init = (url, token) => {
wsurl = url;
accessToken = token;
// 防止重新注册事件
if(hasInit){
return;
}
hasInit = true;
uni.onSocketOpen((res) => { uni.onSocketOpen((res) => {
console.log("WebSocket连接已打开"); console.log("WebSocket连接已打开");
isConnect = true; isConnect = true;
@ -35,8 +27,6 @@ let init = (url, token) => {
if (sendInfo.cmd == 0) { if (sendInfo.cmd == 0) {
heartCheck.start() heartCheck.start()
console.log('WebSocket登录成功') console.log('WebSocket登录成功')
// 登录成功才算连接完成
openCallBack && openCallBack();
} else if (sendInfo.cmd == 1) { } else if (sendInfo.cmd == 1) {
// 重新开启心跳定时 // 重新开启心跳定时
heartCheck.reset(); heartCheck.reset();
@ -48,7 +38,6 @@ let init = (url, token) => {
}) })
uni.onSocketClose((res) => { uni.onSocketClose((res) => {
console.log(res)
console.log('WebSocket连接关闭') console.log('WebSocket连接关闭')
isConnect = false; //断开后修改标识 isConnect = false; //断开后修改标识
closeCallBack && closeCallBack(res); closeCallBack && closeCallBack(res);
@ -64,7 +53,9 @@ let init = (url, token) => {
}) })
}; };
let connect = ()=>{ let connect = (url, token)=>{
wsurl = url;
accessToken = token;
if (isConnect) { if (isConnect) {
return; return;
} }
@ -83,6 +74,18 @@ let connect = ()=>{
}); });
} }
//定义重连函数
let reconnect = (wsurl,accessToken) => {
console.log("尝试重新连接");
if (isConnect){
//如果已经连上就不在重连了
return;
}
rec && clearTimeout(rec);
rec = setTimeout(function() { // 延迟15秒重连 避免过多次过频繁请求重连
connect(wsurl,accessToken);
}, 15000);
};
//设置关闭连接 //设置关闭连接
let close = () => { let close = () => {
@ -142,9 +145,6 @@ function onMessage(callback) {
messageCallBack = callback; messageCallBack = callback;
} }
function onOpen(callback) {
openCallBack = callback;
}
function onClose(callback) { function onClose(callback) {
closeCallBack = callback; closeCallBack = callback;
@ -155,9 +155,9 @@ function onClose(callback) {
export { export {
init, init,
connect, connect,
reconnect,
close, close,
sendMessage, sendMessage,
onMessage, onMessage,
onOpen,
onClose onClose
} }
Loading…
Cancel
Save