mqtt的使用與封裝(vue3+ts)

1. 安裝mqtt

npm i mqtt

2.封裝

  • 新建NotifyMessage.ts 消息返回的類型
export default class NotifyMessage{
    type: string
    source: string
    data: any
    timestamp?: string

    constructor(type: string, source: string, data: any) {
        this.type = type;
        this.source = source;
        this.data = data;
    }
}

  • 新建mqtt.ts 創(chuàng)建mqtt類 (連接、訂閱涧黄、取消訂閱绑洛、收到消息)
import * as mqtt from "mqtt"
import {ISubscriptionGrant, MqttClient} from "mqtt/types/lib/client";
import {IConnackPacket, IDisconnectPacket, IPublishPacket} from "mqtt-packet";
import NotifyMessage from "./NotifyMessage";

export class Mqtt {
  host: string
  port: number
  username: string
  password: string
  path: string
  client?: MqttClient
  topicMap = new Map<string, Set<((message: any, type?:string) => void)>>()

  constructor(host:string, port:number, username:string, password:string, path: string) {
      this.host = host
      this.port = port
      this.username = username
      this.password = password
      this.path = path
      this.connect()
  }

  connect() {
      this.client = mqtt.connect({
          host: this.host,
          port: this.port,
          hostname: this.host,
          username: this.username,
          password: this.password,
          path: this.path,
          protocol: location.protocol === "http:" ? "ws" : "wss",
          keepalive: 15,
      })

      this.client!.once('connect', (packet) => this.onConnect(packet))
      this.client!.on('reconnect', () => console.debug(process.env.VUE_APP_name + " mq reconnect."))
      this.client!.on('disconnect', (packet: IDisconnectPacket) => console.debug(process.env.VUE_APP_name + " mq disconnect.", packet))
      this.client!.on('close', () => console.debug(process.env.VUE_APP_name + " mq close."))
  }

  onConnect(p: IConnackPacket) {
      console.debug(process.env.VUE_APP_name + " connect to mq success. ", p)
      this.client!.removeAllListeners('message')
      this.client!.on('message', (topic, payload, packet) => this.onMessage(topic, payload.toString(), packet))
      if(Array.from(this.topicMap.keys()).length > 0) {
          this.client!.subscribe(Array.from(this.topicMap.keys()), (err: Error | null, granted: ISubscriptionGrant[]) => {
              if(err) {
                  console.error(process.env.VUE_APP_name + " subscribe to mq error: ", err, granted)
              } else {
                  console.debug(process.env.VUE_APP_name + " subscribe to mq granted: ", granted)
              }
          })
      }
  }

  onMessage(topic: string, payload: string, packet: IPublishPacket) {
      try{
          let notify = JSON.parse(payload) as NotifyMessage
          console.debug(notify)

          let topicCBList = this.topicMap.get(topic);
          if(topicCBList) {
              topicCBList.forEach((f) => {
                  try {
                      f(notify.data, notify.type)
                  } catch (e) {
                      console.debug(process.env.VUE_APP_name + " process topic cb fun error.", e)
                  }
              })
          } else {
              console.debug(process.env.VUE_APP_name + " can't find subscribe callback.")
          }
      } catch (e) {

      }

  }

  subscribe(topic:string, callback:(message: any, type?:string) => void ) {
      if(!this.topicMap.has(topic)) {
          this.client?.subscribe(topic, (err: Error | null, granted: ISubscriptionGrant[]) => {
              if(err) {
                  console.error(process.env.VUE_APP_name + " subscribe to mq error: ", err, granted)
              } else {
                  console.debug(process.env.VUE_APP_name + " subscribe to mq granted: ", granted)
              }
          })
          this.topicMap.set(topic, new Set())
      }
      this.topicMap.get(topic)?.add(callback)
  }

  unsubscribe(topic:string, callback?:(message:any) => void) {
      if(this.topicMap.has(topic)) {
          if(callback) {
              this.topicMap.get(topic)?.delete(callback)
          } else {
              this.topicMap.get(topic)?.clear()
          }

          if(this.topicMap.get(topic)!.size <= 0) {
              this.topicMap.delete(topic)
              this.client?.unsubscribe(topic)
          }
      }
  }
}


  • 創(chuàng)建config.json 全局配置數據 --- 這里默認配置mqtt
{
  "logoConfig": {
    "systemTitle": "管理系統(tǒng)"
  },
  "mqttConfig": {
    "host": "",
    "port": 0,
    "username": "admin",
    "password": "admin",
    "path": "/activemq",
    "use": true
  }
}

  • 創(chuàng)建global/customConfig.ts (mqtt配置的類型)
export class CustomConfig {
  mqttConfig?: MqttConfig
  logoConfig?: LogoConfig
  
  constructor(obj:CustomConfig) {
      Object.assign(this, obj)
      if(obj.mqttConfig) {
          this.mqttConfig = new MqttConfig(obj.mqttConfig)
      }
  }
}

export class MqttConfig {
  host:string = ""
  port:number = 61614
  username:string = "admin"
  password:string = "admin"
  path:string = "/activemq"
  use:boolean = false

  constructor(obj:MqttConfig) {
      Object.assign(this, obj)
  }

  getHost():string {
      return this.host === "" ? document.location.hostname : this.host
  }

  getPort():number {
      return this.port === 0 ? parseInt(document.location.port) : this.port
  }

}

export class LogoConfig {
  systemTitle: string = "融合通信管理系統(tǒng)"
}
  • 創(chuàng)建global/index.ts (初始化mqtt方法并連接)
import axios from "axios";
import {Mqtt} from "@/mqtt/mqtt";
import {CustomConfig} from "@/global/customConfig";

export let customConfig: CustomConfig
export let mqttInstants: Mqtt

export function InitCustomConfig() {
    return new Promise<CustomConfig>((resolve, reject) => {
        if(customConfig != null) {
            resolve(customConfig)
        }

        axios.get(process.env.VUE_APP_customConfigPath as string)
            .then(res => {
               if(res.status == 200) {
                   customConfig = res.data
                   customConfig = new CustomConfig(res.data)
                   resolve(customConfig)
               } else {
                   reject(new Error("get custom config failed!"))
               }
            })
            .catch( err => {
                reject(err)
            })
    })
}

export function InitMqtt() {
    let mqttConfig = customConfig.mqttConfig
    if(mqttConfig) {
      if(mqttConfig.use) {
        mqttInstants = new Mqtt(mqttConfig.getHost(), mqttConfig.getPort(),
         mqttConfig.username, mqttConfig.password, mqttConfig.path)
      }
    } else {
        console.error("customConfig.mqttConfig is null.")
    }
}

  • main.ts 中引入 InitMqtt()
...

import {InitCustomConfig, InitMqtt} from "@/global";
// 將自動注冊所有組件為全局組件
import dataV from '@jiaminghi/data-view'


InitCustomConfig().then(config => {
  const app = createApp(App)
  document.title = config.logoConfig?.systemTitle ?? ""
  app.config.globalProperties.$customConfig = config
  app.use(router)
  app.use(store)
  app.use(dataV)
  app.use(ElementPlus, {
    locale: process.env.VUE_APP_LANGUAGE == 'en' ? en : zhCn,
  })
  app.use(VueI18n)
  //注冊所有element plus圖標
  for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
    app.component(key, component)
  }

  InitMqtt()

  ...

  app.mount('#app')

})

使用

<template>

</template>
<script lang='ts' setup>
import { ref, onMounted, onUnmounted } from 'vue'
import { mqttInstants } from '@/global';

const onMessage = (msg:any,type?:string) => {
  console.log('消息:',msg)
}

const mqtopic = '/omc-server/present/alarm'
onMounted(()=>{
  // 訂閱
  mqttInstants.subscribe(mqtopic,onMessage)
})
onUnmounted(()=>{
  // 取消訂閱
  mqttInstants.unsubscribe(mqtopic,onMessage)
})
</script>

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末熬荆,一起剝皮案震驚了整個濱河市锥咸,隨后出現的幾起案子晓淀,更是在濱河造成了極大的恐慌勉吻,老刑警劉巖糟需,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坚芜,死亡現場離奇詭異览芳,居然都是意外死亡,警方通過查閱死者的電腦和手機鸿竖,發(fā)現死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門沧竟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來铸敏,“玉大人,你說我怎么就攤上這事悟泵¤颈剩” “怎么了?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵糕非,是天一觀的道長蒙具。 經常有香客問我,道長朽肥,這世上最難降的妖魔是什么禁筏? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮衡招,結果婚禮上篱昔,老公的妹妹穿的比我還像新娘。我一直安慰自己始腾,他們只是感情好州刽,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著浪箭,像睡著了一般穗椅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上奶栖,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天房待,我揣著相機與錄音,去河邊找鬼驼抹。 笑死,一個胖子當著我的面吹牛拜鹤,可吹牛的內容都是我干的框冀。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼敏簿,長吁一口氣:“原來是場噩夢啊……” “哼明也!你這毒婦竟也來了?” 一聲冷哼從身側響起惯裕,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤温数,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蜻势,有當地人在樹林里發(fā)現了一具尸體撑刺,經...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年握玛,在試婚紗的時候發(fā)現自己被綠了够傍。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片甫菠。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖冕屯,靈堂內的尸體忽然破棺而出寂诱,到底是詐尸還是另有隱情,我是刑警寧澤安聘,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布痰洒,位于F島的核電站,受9級特大地震影響浴韭,放射性物質發(fā)生泄漏丘喻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一囱桨、第九天 我趴在偏房一處隱蔽的房頂上張望仓犬。 院中可真熱鬧,春花似錦舍肠、人聲如沸搀继。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽叽躯。三九已至,卻和暖如春肌括,著一層夾襖步出監(jiān)牢的瞬間点骑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工谍夭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留黑滴,地道東北人。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓紧索,卻偏偏與公主長得像袁辈,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子珠漂,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內容