VUE下封装全局STOMP WebSocket

2,027 阅读1分钟

本示例是全局使用的websocket,初始化成功后,可在任意页面或组件中调用

在store文件夹下新建:websocket.js

import Vue from 'vue'
import Vuex from 'vuex'
import SockJS from "sockjs-client";
import Stomp from "stompjs";
 
Vue.use(Vuex)
 
export default new Vuex.Store({
  state: {
    url:'',
    checkInterval:null,//断线重连时 检测连接是否建立成功
    websocket:null,
    stompClient:null,
    listenerList:[],//监听器列表,断线重连时 用于重新注册监听
  },
  getters: {
    stompClient(state) {
      return function () {
        return state.stompClient;
      }
    }
  },
  mutations: {
    WEBSOCKET_INIT(state,url) {
      if(state.stompClient==null||!state.stompClient.connected) {
        state.url = url
        if(state.stompClient!=null&&state.websocket.readyState=== SockJS.OPEN){
          state.stompClient.disconnect(()=>{
            this.commit('WEBSOCKET_CONNECT')
          })
        }else if(state.stompClient!=null&&state.websocket.readyState=== SockJS.CONNECTING){
          console.log("连接正在建立")
          return;
        }else{
          this.commit('WEBSOCKET_CONNECT')
        }
        if(!state.checkInterval){
          const interval=setInterval(()=>{
            console.log("检测连接:"+state.websocket.readyState)
            if(state.stompClient!=null&&state.stompClient.connected){
              clearInterval(state.checkInterval)
              state.checkInterval=null
              console.log('重连成功')
            }else if(state.stompClient!=null&&state.websocket.readyState!= SockJS.CONNECTING){
              //经常会遇到websocket的状态为open 但是stompClient的状态却是未连接状态,故此处需要把连接断掉 然后重连
              state.stompClient.disconnect(()=>{
                this.commit('WEBSOCKET_CONNECT')
              })
            }
          },2000)
          state.checkInterval=interval
        }
      }else{
        console.log("连接已建立成功,不再执行")
      }
    },
    WEBSOCKET_CONNECT(state){
      const _this = this
      const websock = new SockJS(state.url);
      state.websocket=websock
      // 获取STOMP子协议的客户端对象
      const stompClient = Stomp.over(websock);
      stompClient.debug = null //关闭控制台打印
      stompClient.heartbeat.outgoing = 20000;
      stompClient.heartbeat.incoming = 0;//客户端不从服务端接收心跳包
      // 向服务器发起websocket连接
      stompClient.connect(
        {name: 'test'},  //此处注意更换自己的用户名,最好以参数形式带入
        frame => {
          console.log('链接成功!')
          state.listenerList.forEach(item=>{
            state.stompClient.subscribe(item.topic,item.callback)
          })
          //unsubscribe()可以用来取消客户端对这个目的地destination的订阅
          // stompClient.subscribe("/user/queue/message", msg => {
          //   // this.getData(msg);
          //   console.log(msg)
          // });
        },
        err => {//第一次连接失败和连接后断开连接都会调用这个函数 此处调用重连
          setTimeout(() => {
            _this.commit('WEBSOCKET_INIT', state.url)
          }, 1000)
        }
      );
      state.stompClient = stompClient
    },
    WEBSOCKET_SEND(state, p) {
      state.stompClient.send(p.topic,{},p.data);
    },
    WEBSOCKET_UNSUBSRCIBE(state,p){
      state.stompClient.unsubscribe(p)
      for(let i=0;i<state.listenerList.length;i++){
        if(state.listenerList[i].topic==p){
          state.listenerList.splice(i,1)
          console.log("解除订阅:"+p+" size:"+state.listenerList.length)
          break;
        }
      }
 
    }
  },
  actions: {
    WEBSOCKET_INIT({commit},url) {
      commit('WEBSOCKET_INIT',url)
    },
    WEBSOCKET_SEND({commit}, p) {
      commit('WEBSOCKET_SEND', p)
    },
    WEBSOCKET_UNSUBSRCIBE({commit}, p){
      commit('WEBSOCKET_UNSUBSRCIBE', p)
    }
  }
})

main.js添加引用

//socket
import websocket from './store/websocketStore'
Vue.prototype.$websocket = websocket;

接下来就是在任意需要的地方初始化链接,我是在用户登录成功,进入主界面后

created(){
this.$websocket.dispatch('WEBSOCKET_INIT',"http://192.168.0.103:8084/websocket")
},

链接初始化完成以后,就可以在任意界面或组件中注册监听主题或发送消息了,为了防止用户刷新的当前页面就需要注册监听,所以我用了个方法轮询,确认链接可用后再注册

let x = {
    WebSocket:'ws://10.1.147.113:9660/ws/websocket?token='+this.token,
    SockJS:'http://10.1.147.113:9660/ws?token='+this.token
}
this.$websocket.dispatch('WEBSOCKET_INIT',x)
const _this=this
const stompClient=this.$websocket.getters.stompClient()
const interval=setInterval(()=>{
    if(stompClient!=null&&stompClient.connected){
        clearInterval(interval)
        stompClient.subscribe("/topic/billStatus",msg=>{
        this.$store.dispatch('user/hbdata')
        _this.$notify({
            title: '成功',
            message: '端口连接成功',
            type: 'success',
            duration: 2000
        })
     })
    }else{
    console.log("等待连接成功")
    }
},500)