最近嘛,遇到了客户使用MQTT发布消息。而我们则需把这些消息获取并解析进我们自己的系统中,并且对这些数据进行存储,这些就需要我们熟悉MQTT的使用,话不多说,搞起。
因我们项目使用的是SpringBoot,因此在pom中添加MQTT的相关依赖,因仅涉及订阅,顾不考虑发布等。
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.5</version>
</dependency>
创建MQTT的配置类(MyMQTTClient)与回调类(MQTTReceiveCallBack)。
@Component
public class MyMQTTClient {
private static final String HOST = "tcp://ip:port";
private static final String userName = "username";
private static final String passWord = "password";
private static String CLIENTID = UUID.randomUUID().toString().toUpperCase();
private MqttClient client;
private static volatile MyMQTTClient mqttClient = null;
public static MyMQTTClient getInstance() {
if (mqttClient == null) {
synchronized (MyMQTTClient.class) {
if (mqttClient == null) {
mqttClient = new MyMQTTClient();
}
}
}
return mqttClient;
}
private MyMQTTClient() {
connect();
}
/**
* 创建连接
*/
private void connect() {
try {
//初始化连接设置对象
MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
//true可以安全地使用内存持久性作为客户端断开连接时清除的所有状态
mqttConnectOptions.setCleanSession(true);
mqttConnectOptions.setConnectionTimeout(30);//设置连接超时
mqttConnectOptions.setUserName(userName); // 设置连接的用户名
mqttConnectOptions.setPassword(passWord.toCharArray());// 设置连接的密码
client = new MqttClient(HOST,CLIENTID, new MemoryPersistence());
client.setCallback(new MQTTReceiveCallBack());//执行回调
client.connect(mqttConnectOptions);//创建连接
client.subscribe("#",1);
} catch (MqttException e) {
e.printStackTrace();
}
}
/**
* 订阅主题
*
* @param topic qos默认为1
*/
public void subTopic(String topic) {
try {
client.subscribe(topic, 1);
} catch (MqttException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 清空主题
* @param topic
*/
public void cleanTopic(String topic) {
try {
client.unsubscribe(topic);
} catch (MqttException e) {
e.printStackTrace();
}
}
}
@Component
public class MQTTReceiveCallBack implements MqttCallback {
//Service层用于数据处理
private static DealMessageService dealMessageService;
@Resource
private void setDealMessageService(DealMessageService dealMessageService){
this.dealMessageService = dealMessageService;
}
/**
* 断连后重新连接并订阅相关主题
*/
@Override
public void connectionLost(Throwable throwable) {
MyMQTTClient client = MyMQTTClient.getInstance();
client.subTopic("#");
}
/**
* 消费消息
* @param s 主题
* @param mqttMessage 主体消息
* @throws Exception
*/
@Override
public void messageArrived(String s, MqttMessage mqttMessage) throws Exception {
String msg = new String(mqttMessage.getPayload());
if(s.startsWith("IO-CT")){
dealMessageService.dealMessage(s,msg);
}else{
dealMessageService.init();
}
}
/**
* 接收到已经发布的 QoS 1 或 QoS 2 消息的传递令牌时调用
*/
@Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
}
}
在回调类中DealMessageService为处理数据并塞入数据库的Service层。因我们是需要订阅所有的所以主题是“#”,如果有具体的订阅主题可替换至所需主题名称。MessageArrived(String s, MqttMessage mqttMessage)是订阅消息的主体信息,s表示订阅主题,String msg = new String(mqttMessage.getPayload())为主体信息。
使用 log.info("MQTT接收到数据:" + s + "::" + msg);打印出来的示例信息如下所示
MQTT接收到数据:IO-CT/4C/status/YSC82B96012F48::{"signal":-52,"status_a":[0,0,0,0]}
如此获取到信息之后则可以在Service层中按常规的数据层交互即可。