Java代码:
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
/**
* @author zhangzg
* @ClassName: TicketWebSocket
* @Description: 用来推送消息
* @date 2018/8/16 10:55
*/
@ServerEndpoint("/websocket/{userId}")
@Component
@Slf4j
public class TicketWebSocket {
//用来存放当前连接的session
private Session session;
//key为userId,value为Set<Session>
private static Map<String, Set<Session>> sessionPool = new HashMap<String, Set<Session>>();
//key为Session的id,value为userId
private static Map<String, String> sessionIds = new HashMap<String, String>();
/**
* @Description: 用户连接时触发,将userId与session存进map,session存进Set
* @param: [session, userId]
* @return: void
* @auther: zhangzg
* @date: 2018/8/17 9:22
*/
@OnOpen
public void onOpen(Session session, @PathParam(value = "userId") String userId) {
this.session = session;
Set<Session> sessions = new HashSet<Session>();
if (sessionPool.get(userId) != null) {
sessions = sessionPool.get(userId);
}
sessions.add(session);
sessionPool.put(userId, sessions);
sessionIds.put(session.getId(), userId);
log.debug("user:" + userId + "session:" + session.getId() + "连接成功");
}
/**
* @Description: 收到消息时触发
* @param: [message]
* @return: void
* @auther: zhangzg
* @date: 2018/8/17 9:23
*/
@OnMessage
public void onMessage(String message) {
System.out.println("当前发送人sessionid为" + session.getId() + "内容:" + message);
// System.out.println("当前发送人sessionid为" + session.getId() + "标题:" + message.getTitle()+"内容:"+message.getContent());
}
/**
* @Description: 连接关闭时触发,从map中移除session与userId
* @param: []
* @return: void
* @auther: zhangzg
* @date: 2018/8/17 9:24
*/
@OnClose
public void onClose() {
log.debug("sessionId为" + session.getId() + "的关闭");
//从中取出userId
String userId = sessionIds.get(session.getId());
//根据userId找到对应Set,再从Set中移除该Session
Set<Session> sessions = sessionPool.get(userId);
if (sessions != null) {
sessions.remove(session);
}
//覆盖原来的sessionPool中的数据
sessionPool.put(userId, sessions);
sessionIds.remove(session.getId());
}
/**
* 发生错误时触发
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("webSocket发生错误");
error.printStackTrace();
log.debug("sessionId为" + session.getId() + "的webSocket关闭");
//从中取出userId
String userId = sessionIds.get(session.getId());
//根据userId找到对应Set,再从Set中移除该Session
Set<Session> sessions = sessionPool.get(userId);
if (sessions != null) {
sessions.remove(session);
}
//覆盖原来的sessionPool中的数据
sessionPool.put(userId, sessions);
sessionIds.remove(session.getId());
}
/**
* @Description: 发送消息的方法,若用户不在线则不发送
* @param: [message, userId]
* @return: void
* @auther: zhangzg
* @date: 2018/8/17 9:27
*/
public static void sendMessage(TicketMessage message, String userId) {
Set<Session> sessions = sessionPool.get(userId);
if (sessions != null) {
for (Session s : sessions) {
try {
System.out.println(JSON.toJSON(message));
s.getBasicRemote().sendText(JSON.toJSON(message).toString());
} catch (IOException e) {
log.error("IOException异常,发送信息失败");
e.printStackTrace();
}
}
} else {
log.debug("session中不存在userId为" + userId + "的用户");
}
}
/**
* @Description: 返回当前的在线用户数
* @param: []
* @return: int
* @auther: zhangzg
* @date: 2018/8/17 9:32
*/
public static int getOnlineNum() {
return sessionPool.size();
}
/**
* @Description: 返回在线的所有用户的userId,返回结果以“,”隔开
* @param: []
* @return: java.lang.String
* @auther: zhangzg
* @date: 2018/8/17 9:34
*/
public static String getOnlineUsers() {
StringBuffer users = new StringBuffer();
for (String key : sessionIds.keySet()) {
users.append(sessionIds.get(key) + ",");
}
return users.toString();
}
/**
* @Description: 给在线的所有用户推送msg
* @param: [msg]
* @return: void
* @auther: zhangzg
* @date: 2018/8/17 9:36
*/
public static void sendAll(TicketMessage msg) {
for (String key : sessionIds.keySet()) {
sendMessage(msg, sessionIds.get(key));
}
}
/**
* @Description: 给persons当中的用户发送msg
* @param: [msg, persons]
* @return: void
* @auther: zhangzg
* @date: 2018/8/17 9:37
*/
public static void SendMany(TicketMessage msg, Set<String> persons) {
for (String userId : persons) {
sendMessage(msg, userId);
}
}
/**
* @Description: 判断用户是否在线
* @param: [userId]
* @return: boolean
* @auther: zhangzg
* @date: 2018/8/21 15:33
*/
public static boolean isOnline(String userId) {
if (sessionPool.get(userId) != null) {
log.debug("userId" + userId + "在线");
return true;
}
log.debug("userId" + userId + "不在线");
return false;
}
}
Vue代码:
只用了initWs()方法和心跳检测方法,其他的可以作为参考
<template>
<!-- <Card>
<div>
<Button type="primary" @click="threadPoxi()" icon="plus">发送消息</Button>
<Button type="primary" @click="sendMessageByJava()" icon="plus">发送消息使用后台方法</Button>
</div>
</Card> -->
</template>
<script>
import { baseURL, sendMessage } from '@/api/api'
export default {
name: "TicketWebSocket",
data () {
return {
user:{},
userId:'',
websocket: null,
msg:{
msgTitle: '12123',
content: '1325154564',
sender: '',
receiver: '6',
bussinessId: '1'
},
errorTaskFlag:false,
websocket_connected_count: 0,
timeout: 7100000, // 2小时发一次心跳,比server端设置的连接时间稍微小一点,在接近断开的情况下以通信的方式去重置连接时间。
serverTimeoutObj: null
}
},
methods: {
sendMessageByJava(){
let params={
msgTitle: this.msg.msgTitle,
content: this.msg.content,
sender: '6',
receiver: this.msg.receiver,
bussinessId: this.msg.bussinessId
};
sendMessage(params).then((res) =>{
// console.log("到这而了");
console.log(res.data.resultData)
})
},
threadPoxi(){ // 实际调用的方法 如果ws已经连接则直接发送消息;如正在开启状态,则等待300毫秒,再发送消息;若未开启 ,则等待500毫秒,再发送消息。
// 参数
const agentData = "从前台发出的信息";
//若是ws开启状态
if (this.websocket.readyState === this.websocket.OPEN) {
this.websocketsend(agentData)
}
// 若是 正在开启状态,则等待300毫秒
else if (this.websocket.readyState === this.websocket.CONNECTING) {
let that = this;//保存当前对象this
setTimeout(function () {
that.websocketsend(agentData)
}, 300);
}
// 若未开启 ,则等待500毫秒
else {
this.initWs();
let that = this;//保存当前对象this
setTimeout(function () {
that.websocketsend(agentData)
}, 500);
}
},
initWs () {
// websocket连接
// let websocket_connected_count = 0;
let onclose_connected_count = 0;
if ('WebSocket' in window) {
let ws = 'ws://';
if(window.location.protocol == 'https:') ws = 'wss://';
this.websocket = new WebSocket(ws + baseURL.split("://")[1] + "/websocket/" + JSON.parse(localStorage.getItem('userFront')).orgUser.id);
}
else {
alert('Sorry, websocket not supported by your browser.')
}
//数据接收
// this.websocket.onmessage = this.websocketonmessage;
// 连接成功建立的回调方法
this.websocket.onopen = (e) => {
clearInterval(this.serverTimeoutObj);
this.heartCheck();
this.errorTaskFlag = false;
// console.log("连接成功")
};
// 连接发生错误,连接错误时会继续尝试发起连接(5秒重试一下)
this.websocket.onerror = () => {
// console.log("onerror连接发生错误");
setTimeout(() => {
this.initWs()
},5000)
};
// 接受到消息的回调方法
this.websocket.onmessage = (e) => {
// console.log("接受到消息了");
let message = e.data;
if(message){
//执行接收到消息的操作,一般是刷新UI
}
this.$Notice.info({
title: '你有一条新的消息!'
});
this.$emit('new-message','msg');
this.$store.commit("refreshMsg", true);
this.$store.commit("freshMsgList", true);
};
// 接受到服务端关闭连接时的回调方法
this.websocket.onclose = () => {
// console.log("关闭了");
// Tip("onclose断开连接");
}
},
// 心跳检测, 每隔一段时间检测连接状态,如果处于连接中,就向server端主动发送消息,来重置server端与客户端的最大连接时间,如果已经断开了,发起重连。
heartCheck() {
this.serverTimeoutObj = setInterval(() => {
if(this.websocket && this.websocket.readyState && this.websocket.readyState === 1){
const currentDate = new Date();
const hour = currentDate.getHours() < 10 ? '0'+currentDate.getHours() : currentDate.getHours();
const minute = currentDate.getMinutes() < 10 ? '0'+currentDate.getMinutes() : currentDate.getMinutes();
const seconds = currentDate.getSeconds() < 10 ? '0'+currentDate.getSeconds() : currentDate.getSeconds();
// console.log("连接状态,发送消息保持连接" + `${hour}:${minute}:${seconds}`);
this.websocket.send("ping");
}else{
// console.log("断开状态,尝试重连");
this.initWs();
}
}, this.timeout)
}
},
created(){
this.initWs();
},
beforeDestroy() {
clearInterval(this.serverTimeoutObj);
this.websocket.close();
}
}
</script>
<style scoped>
</style>