1.首先在一台准备好的Linux服务器安装EMQX,作为MQTT服务器
1.wget https://www.emqx.com/zh/downloads/broker/5.0.21/emqx-5.0.21-el8-amd64.tar.gz
2.mkdir -p emqx && tar -zxvf emqx-5.0.21-el8-amd64.tar.gz -C emqx
3.启动 EMQX
./emqx/bin/emqx start
放行端口:
18083(mqtt后台端口 )
8083(mqtt的websocket连接端口 )
1883(mqtt的TCP连接端口 )
2.访问EMQX客户端:服务器IP:18083,如果出现如下页面,说明安装成功
初始账号:admin
初始密码:public
登录进去会提示修改密码,将密码改成自己的即可
springboot项目引入MQTT
一、引入依赖
<!--MQTT协议依赖-->
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.integration/spring-integration-mqtt -->
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-mqtt</artifactId>
<version>5.4.3</version>
</dependency>
二、新建类:MyMqttServer.java(初始化mqtt,发布和订阅主题的类)
package com.system.mqttMessage;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import java.util.*;
/**
* @author wangghua
* @ClassName MyMqttClient
* @描述:
* @datetime 2023年 4月 28日 14:34
*/
@Async
public class MyMqttServer {
private static final Logger logger = LoggerFactory.getLogger(MyMqttServer.class);
public static MqttClient mqttClient = null;
private static MemoryPersistence memoryPersistence = null;
private static MqttConnectOptions mqttConnectOptions = null;
private static String clientId = "serviceId:20230428123456789";
private static String mqttuser = "admin";
private static String password = "你修改的密码";
private static String Host = "tcp://服务器IP:1883";
/**
* 保存topic,断开重连,重新订阅
*/
private static Set<String> topicSet = new HashSet<>();
/**
* 初始化客户端,连接mqtt服务器
*/
public static void init() {
memoryPersistence = new MemoryPersistence();
try {
mqttClient = new MqttClient(Host, clientId, memoryPersistence);
} catch (MqttException e) {
e.printStackTrace();
}
mqttConnectOptions = new MqttConnectOptions();
mqttConnectOptions.setCleanSession(false);
mqttConnectOptions.setConnectionTimeout(30);
mqttConnectOptions.setKeepAliveInterval(45);
//设置自动重连
mqttConnectOptions.setAutomaticReconnect(true);
//下面两个存在就加上
mqttConnectOptions.setUserName(mqttuser);
mqttConnectOptions.setPassword(password.toCharArray());
if (!mqttClient.isConnected()) {
try {
mqttClient.connect(mqttConnectOptions);
mqttClient.setCallback(new PublishCallBack());
logger.info("mqtt 连接成功!");
} catch (MqttException e) {
e.printStackTrace();
}
} else {
logger.info("mqttClient is error");
}
}
/**
* 断开重连,重新订阅之前的topic,60秒重试一次
*/
public synchronized static void reConnect() {
while (true) {
if (null != mqttClient) {
if (!mqttClient.isConnected()) {
if (null != mqttConnectOptions) {
try {
mqttClient.connect(mqttConnectOptions);
mqttClient.setCallback(new PublishCallBack());
} catch (MqttException e) {
e.printStackTrace();
}
if (mqttClient.isConnected()) {
String[] topicArr = new String[topicSet.size()];
topicSet.toArray(topicArr);
logger.info("主题列表:{}", topicArr);
subTopic(topicArr);
break;
}
} else {
logger.info("mqttConnectOptions is null");
}
} else {
logger.info("mqttClient is null or connect");
}
} else {
init();
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("断开重连错误信息:"+e.getMessage());
e.printStackTrace();
}
}
}
/**
* 关闭连接
*/
public static void closeConnect() {
//关闭存储方式
if (null != memoryPersistence) {
try {
memoryPersistence.close();
topicSet.clear();
} catch (MqttPersistenceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
logger.info("memoryPersistence is null");
}
// 关闭连接
if (null != mqttClient) {
if (mqttClient.isConnected()) {
try {
mqttClient.disconnect();
mqttClient.close();
} catch (MqttException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
System.out.println("mqttClient is not connect");
}
} else {
System.out.println("mqttClient is null");
}
}
// 订阅主题
public static void subTopic(String[] topicArr) {
System.out.println("订阅主题 = " + Arrays.deepToString(topicArr));
for (String topic : topicArr) {
topicSet.add(topic);
}
if (null != mqttClient && mqttClient.isConnected()) {
try {
mqttClient.subscribe(topicArr);
} catch (MqttException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
logger.info("mqttClient is error");
}
}
/**
* 清空主题
*
* @param topic
*/
public static void cleanTopic(String topic) {
if (null != mqttClient && !mqttClient.isConnected()) {
try {
mqttClient.unsubscribe(topic);
topicSet.remove(topic);
} catch (MqttException e) {
e.printStackTrace();
}
} else {
logger.info("mqttClient is error,Maybe the MQTT connection is down....");
}
}
/**
* 发布消息
* @param pubTopic
* @param message
*/
public static void publishMessage(String pubTopic, String message) {
//打开连接
MyMqttServer.init();
if (null != mqttClient && mqttClient.isConnected()) {
MqttMessage mqttMessage = new MqttMessage();
mqttMessage.setQos(2);
mqttMessage.setPayload(message.getBytes());
MqttTopic topic = mqttClient.getTopic(pubTopic);
if (null != topic) {
try {
MqttDeliveryToken publish = topic.publish(mqttMessage);
if (!publish.isComplete()) {
logger.info("mqtt消息发布成功");
}
} catch (MqttException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} else {
MyMqttServer.reConnect();
}
//关闭连接
MyMqttServer.closeConnect();
}
}
三、新建类:PublishCallBack.java(处理收到的消息)
package com.system.mqttMessage;
import com.alibaba.fastjson.JSONObject;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author wangghua
* @ClassName PublishCallBack
* @描述:
* @datetime 2023年 4月 28日 14:37
*/
public class PublishCallBack implements MqttCallback {
private static final Logger logger = LoggerFactory.getLogger(PublishCallBack.class);
public void connectionLost(Throwable throwable) {
logger.info("断开连接,正在准备重连");
throwable.printStackTrace();
MyMqttServer.reConnect();
}
public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
//subscribe后会执行到这里
System.out.println("消息的主题是:"+topic);
System.out.println("消息的Qos是:"+mqttMessage.getQos());
System.out.println("消息的ID是:"+mqttMessage.getId());
String message = new String(mqttMessage.getPayload());
JSONObject jsonObject = JSONObject.parseObject(message);
System.out.println("消息的内容是:"+message);
System.out.println("转化的jsonObject消息的内容是:"+jsonObject);
}
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
//publish可以执行到这里
System.out.println("This is deliveryComplete method----->"+iMqttDeliveryToken.isComplete());
}
}
三、增加发布消息的接口
package com.system.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import jodd.util.StringUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import springfox.documentation.annotations.ApiIgnore;
import java.util.Date;
import java.util.List;
@ApiIgnore
@Controller
@RequestMapping("/api/msg")
@Api(tags = "Websocket")
public class WebsocketController {
public @ResponseBody
@GettMapping("/sendWebsocketMsg")
@ApiOperation("消息发送")
String sendWebsocketMsg(String data,String topic){
MyMqttServer.publishMessage(topic,data);
return "发送成功";
}
}
这是发布成功的控制台打印
Vue引入MQTT
一、下载依赖
npm install mqtt --save
二、完整代码
<template>
<div class="hello">
<h1>收到的消息:{{myMsg}}</h1>
<el-input
v-model="sendMessage"
placeholder="请输入需要发送的消息"
clearable
/>
<button @click="mqttPublish">发送</button>
</div>
</template>
<script>
import mqtt from "mqtt";
export default {
name: "HelloWorld",
data() {
return {
client: "",
sendMessage: "",
myMsg:"",
topicMqtt:"messageTopic"
};
},
destroyed: function() {
//页面销毁时关闭长连接
// this.websocketclose();
if (this.client.end) this.client.end();
},
mounted() {
this.initMqtt();
this.mqttReceive();
},
methods: {
/**
* @name:初始化mqtt
* @msg:
* @param {*}
* @return {*}
*/
initMqtt() {
let vm = this;
let commonApi = "ws://服务器IP:8083/mqtt";
var mqtt = require("mqtt");
var options = {
//mqtt客户端的id
clientId: "system-"+ Math.random().toString(16).substr(2, 8),
};
vm.client = mqtt.connect(commonApi, options);
this.client.on("connect", function () {
console.log("连接成功....");
});
//如果连接错误,打印错误
vm.client.on("error", function (err) {
console.log("err=>", err);
vm.client.end();
});
},
/**
* @name:发布mqtt消息
* @msg:
* @param {*}
* @return {*}
*/
mqttPublish() {
this.client.publish(this.topicMqtt, JSON.stringify(this.sendMessage));
},
/**
* @name:接收mqtt消息
* @msg:
* @param {*}
* @return {*}
*/
mqttReceive() {
const vm = this;
vm.client.subscribe(vm.topicMqtt,{ qos: 1 }, function (err) {
if (!err) {
console.log("subscribe success!");
} else {
//打印错误
console.log("err", err);
}
});
vm.client.on("message", function (topic, message) {
vm.myMsg = message.toString();
console.log('收到来自',topic,'的信息',message.toString())
vm.$notify({
title: '新消息通知',
message: message.toString(),
dangerouslyUseHTMLString: true,
// position: 'bottom-right',
duration: 0,//0为手动关闭消息提示
type: 'warning',
});
});
},
},
};
</script>