当前位置:   article > 正文

springboot websocket 实时刷新 添加心跳机制(亲测可用版)_springboot websocket 心跳

springboot websocket 心跳

思路

在我之前的一篇文章当中写到了websocket的实时刷新,但是有个问题没有解决,就是长时间没有数据的时候,这个连接就会自动断开,然后再次进行连接的话,需要再次进行连接。如果加入心跳机制的话,10秒钟客户端向服务端发送数据,服务端接收到数据,发条消息,告诉客户端我还在,客户端接收到消息,知道我们还是连接的状态,就没有必要再进行连接。如果客户端发送的消息,服务端没有对这个消息进行响应,则说明已经断开连接,则需要重新连接。
服务端代码如下:

package cn.lsmsp.alarm.snmp.config;

import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;

@Component
@ServerEndpoint("/websocket/{shopId}")
//此注解相当于设置访问URL
public class WebSocket {

    private Logger logger = LoggerFactory.getLogger(WebSocket.class);

    private Session session;

    private static CopyOnWriteArraySet<WebSocket> webSockets = new CopyOnWriteArraySet<>();
    private static Map<String, Session> sessionPool = new HashMap<String, Session>();

    @OnOpen
    public void onOpen(Session session, @PathParam(value = "shopId") String shopId) throws InterruptedException {
        this.session = session;
        webSockets.add(this);
//        sessionPool.put(shopId, session);
//        System.out.println("【websocket消息】有新的连接,总数为:"+webSockets.size());
        System.out.println("【websocket消息】有新的连接啦!!!"+LocalDateTime.now());
//        webSocketXdxService.xdxTest(shopId);
    }

    @OnClose
    public void onClose(Session session) {
        try {
            webSockets.remove(this);
            session.close();
            System.out.println("【websocket消息】连接断开,总数为:" + webSockets.size());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @OnMessage
    public void onMessage(String message) {
        logger.info("【websocket消息】收到客户端消息:" + message);
        Map<String, Object> maps = new HashMap<>();
        maps.put("type", message);
        this.sendAllMessage(JSON.toJSONString(maps));
    }

    // 此为广播消息
    public void sendAllMessage(String message) {
        for (WebSocket webSocket : webSockets) {
            System.out.println("【websocket消息】广播消息:" + message);
            try {
                webSocket.session.getAsyncRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    // 此为单点消息 (发送文本)
    public void sendTextMessage(String shopId, String message) {
        Session session = sessionPool.get(shopId);
        if (session != null) {
            try {
                session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    // 此为单点消息 (发送对象)
    public void sendObjMessage(String shopId, Object message) {
        Session session = sessionPool.get(shopId);
        if (session != null) {
            try {
                session.getAsyncRemote().sendObject(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95

相对于上次,结合我这边的业务进行了调整,删除了session的存储,就变成了一个用户多个聊天窗口的那种概念。

客户端代码如下:

<template>    
	<div>       
		<h1>测试webSocket</h1>
        <div id ="aaa" style="height: 300px; overflow-y: scroll; background: #333; color: #aaa; padding: 10px;"></div>
    </div>
</template>
<script>
	var that;
export default {
    data(){
        return {
            data:0,
            timeout: 30 * 1000,//30秒一次心跳
            timeoutObj: null,//心跳心跳倒计时
            serverTimeoutObj: null,//心跳倒计时
            timeoutnum: null,//断开 重连倒计时
            websocket: null,
        }
	},
	created() { // 页面创建生命周期函数  
        that = this;
		that.initWebSocket()
	},        
	destroyed: function () { // 离开页面生命周期函数              
		that.websocketclose();
	},        
	methods: {            
		initWebSocket: function () {                
			// WebSocket与普通的请求所用协议有所不同,ws等同于http,wss等同于https                
			that.websocket = new WebSocket("wss://127.0.0.1:9231/kh_snmptrap/websocket/lsmsp");
			that.websocket.onopen = that.websocketonopen;
			that.websocket.onerror = that.websocketonerror;
			that.websocket.onmessage = that.setOnmessageMessage;
			that.websocket.onclose = that.websocketclose;
            // 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
            // window.onbeforeunload = that.onbeforeunload
        },
        reconnect: function () { // 重新连接
            if(that.lockReconnect) return;
            that.lockReconnect = true;
            //没连接上会一直重连,设置延迟避免请求过多
            that.timeoutnum && clearTimeout(that.timeoutnum);
            that.timeoutnum = setTimeout(() => {
                //新连接
                that.initWebSocket();
                that.lockReconnect = false;
            }, 5000);
        },
        reset: function () { // 重置心跳
            // 清除时间
            clearTimeout(that.timeoutObj);
            clearTimeout(that.serverTimeoutObj);
            // 重启心跳
            that.start();
        },
        start: function () { // 开启心跳
            that.timeoutObj && clearTimeout(that.timeoutObj);
            that.serverTimeoutObj && clearTimeout(that.serverTimeoutObj);
            that.timeoutObj = setTimeout(() => {
                // 这里发送一个心跳,后端收到后,返回一个心跳消息,
                if (that.websocket && that.websocket.readyState == 1) { // 如果连接正常
                    that.websocketsend('heartbeat');
                } else { // 否则重连
                    that.reconnect();
                }
                that.serverTimeoutObj = setTimeout(() => {
                    //超时关闭
                    that.websocket.close();
                }, that.timeout);

            }, that.timeout)
        },
        setOnmessageMessage: function(event) {
            let obj = JSON.parse(event.data);
            // console.log("obj",obj)
            switch(obj.type) {
                case 'heartbeat':
                    //收到服务器信息,心跳重置
                    that.reset();
                    break;
                case 'sendMessage':
                    that.data = obj.data
                    console.log("接收到的服务器消息:",JSON.stringify(obj.data,null,4))
                    document.getElementById('aaa').innerHTML=JSON.stringify(obj.data,null,4)
            }
        },
		websocketonopen: function () {
            //开启心跳
            that.start();
            console.log("WebSocket连接成功!!!"+new Date()+"----"+that.websocket.readyState);
		},              
		websocketonerror: function (e) {                
			console.log("WebSocket连接发生错误" + e);              
		},              
		websocketonmessage: function (e) {                
			console.log(e.data);                // console.log(e);
            document.getElementById('aaa').innerHTML=e.data
        },
		websocketclose: function (e) {
            that.websocket.close();
            console.log("connection closed ");
		},
        websocketsend(messsage) {
            that.websocket.send(messsage)
        },
        closeWebSocket() { // 关闭websocket
            that.websocket.close()
        }
	}    
}
</script>
<style >
</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113

相对于删上次,加入了心跳的时间。这样的话客户端会收到两种类型的数据,heartbeat和sendMessage,便于区别哪个是心跳数据,哪个是发送的数据。还有一点,我这里是https的请求,如果你是http请求的话,把wss://127.0.0.1:9231改为ws://127.0.0.1:9231。其它想知道的,参考我之前的一篇文章:springboot websocket 实时刷新(亲测可用版)

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号