集成mqtt协议 并以线程池来读取请求

application.yml

mqtt:

username: admin # 用户名

password: 123456 # 密码

hostUrl: tcp://broker.emqx.io:1883 # tcp://ip:端口

clientId: mqttx_59ba2b45 # 客户端id

defaultTopic: cest # 订阅主题

timeout: 100 # 超时时间 (单位:秒)

keepalive: 60 # 心跳 (单位:秒)

enabled: true # 是否使用mqtt功能

----------------------------MqttPushClient.java

package com.aide.mqtt.protocols;

import lombok.Getter;

import lombok.Setter;

import lombok.extern.slf4j.Slf4j;

import org.eclipse.paho.client.mqttv3.*;

import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component

@Slf4j

public class MqttPushClient {

@Getter

@Setter

private static MqttClient client; // MQTT客户端

@Resource

private PushCallback pushCallback; // 推送回调

/**

* 客户端连接

*

* @param host ip+端口

* @param clientID 客户端Id

* @param username 用户名

* @param password 密码

* @param timeout 超时时间

* @param keepalive 保留数

*/

public void connect(String host, String clientID, String username, String password, int timeout, int keepalive) {

MqttClient client;

try {

client = new MqttClient(host, clientID, new MemoryPersistence());

MqttConnectOptions options = new MqttConnectOptions();

options.setCleanSession(true);

options.setUserName(username);

options.setPassword(password.toCharArray());

options.setConnectionTimeout(timeout);

options.setKeepAliveInterval(keepalive);

MqttPushClient.setClient(client);

client.setCallback(pushCallback);

client.connect(options);

} catch (Exception e) {

log.error("连接失败:{}", e.getMessage());

}

}

/**

* 发布

*

* @param qos 连接方式

* @param retained 是否保留

* @param topic 主题

* @param pushMessage 消息体

*/

public void publish(int qos, boolean retained, String topic, String pushMessage) {

MqttMessage message = new MqttMessage();

message.setQos(qos);

message.setRetained(retained);

message.setPayload(pushMessage.getBytes());

MqttTopic mTopic = MqttPushClient.getClient().getTopic(topic);

if (null == mTopic) {

log.error("topic不存在:{}", topic);

}

MqttDeliveryToken token = null;

try {

if (mTopic != null) {

token = mTopic.publish(message);

}

if (token != null) {

token.waitForCompletion();

}

} catch (MqttException e) {

log.error("发布失败:{}", e.getMessage());

}

}

/**

* 订阅某个主题

*

* @param topic 主题

* @param qos 连接方式

*/

public void subscribe(String topic, int qos) {

log.info("开始订阅主题:{}", topic);

try {

MqttPushClient.getClient().subscribe(topic, qos);

} catch (MqttException e) {

log.error("订阅主题失败:{}", e.getMessage());

}

}

}

-----------------------------------------------MqttConfig.java

package com.aide.mqtt.protocols;

import lombok.Data;

import org.springframework.boot.context.properties.ConfigurationProperties;

import org.springframework.context.annotation.Bean;

import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component

@ConfigurationProperties("mqtt")

@Data

public class MqttConfig {

@Resource

private MqttPushClient mqttPushClient;

/**

* 用户名

*/

private String username;

/**

* 密码

*/

private String password;

/**

* 连接地址

*/

private String hostUrl;

/**

* 客户Id

*/

private String clientId;

/**

* 默认连接话题

*/

private String defaultTopic;

/**

* 超时时间

*/

private int timeout;

/**

* 保持连接数

*/

private int keepalive;

/**

* mqtt功能使能

*/

private boolean enabled;

@Bean

public MqttPushClient getMqttPushClient() {

if (enabled) {

mqttPushClient.connect(hostUrl, clientId, username, password, timeout, keepalive);//连接

// 使用通配符订阅所有设备的报告主题

mqttPushClient.subscribe("device/+/report", 0);

// 使用通配符订阅所有设备的命令主题

mqttPushClient.subscribe("device/+/send", 0);

// 使用通配符订阅所有设备的原始数据报告主题

mqttPushClient.subscribe("device/+/raw_data_report", 0);

}

return mqttPushClient;

}

}

-------------------------------------MqttConfig.java

package com.aide.mqtt.protocols;

import lombok.Data;

import org.springframework.boot.context.properties.ConfigurationProperties;

import org.springframework.context.annotation.Bean;

import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component

@ConfigurationProperties("mqtt")

@Data

public class MqttConfig {

@Resource

private MqttPushClient mqttPushClient;

/**

* 用户名

*/

private String username;

/**

* 密码

*/

private String password;

/**

* 连接地址

*/

private String hostUrl;

/**

* 客户Id

*/

private String clientId;

/**

* 默认连接话题

*/

private String defaultTopic;

/**

* 超时时间

*/

private int timeout;

/**

* 保持连接数

*/

private int keepalive;

/**

* mqtt功能使能

*/

private boolean enabled;

@Bean

public MqttPushClient getMqttPushClient() {

if (enabled) {

mqttPushClient.connect(hostUrl, clientId, username, password, timeout, keepalive);//连接

// 使用通配符订阅所有设备的报告主题

mqttPushClient.subscribe("device/+/report", 0);

// 使用通配符订阅所有设备的命令主题

mqttPushClient.subscribe("device/+/send", 0);

// 使用通配符订阅所有设备的原始数据报告主题

mqttPushClient.subscribe("device/+/raw_data_report", 0);

}

return mqttPushClient;

}

}

-----------------------------------------PushCallback.java

package com.aide.mqtt.protocols;

import com.aide.mqtt.service.TopicHandlerService;

import com.aide.mqtt.service.impl.DeviceRawDataHandlerImpl;

import com.aide.mqtt.service.impl.DeviceReportHandlerImpl;

import com.aide.mqtt.service.impl.DeviceSubscribingHandlerImpl;

import lombok.extern.slf4j.Slf4j;

import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;

import org.eclipse.paho.client.mqttv3.MqttCallback;

import org.eclipse.paho.client.mqttv3.MqttClient;

import org.eclipse.paho.client.mqttv3.MqttMessage;

import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;

import javax.annotation.Resource;

import java.util.HashMap;

import java.util.Map;

import java.util.concurrent.BlockingQueue;

import java.util.concurrent.LinkedBlockingQueue;

import java.util.concurrent.ThreadPoolExecutor;

import java.util.concurrent.TimeUnit;

@Component

@Slf4j

public class PushCallback implements MqttCallback {

private MqttClient client;

private final Map<String, TopicHandlerService> handlerMap = new HashMap<>(); // 主题与处理器的映射

@Resource

private MqttConfig mqttConfig;

// 创建一个阻塞队列,用于存储待处理的任务

private final BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>();

// 创建自定义线程池,核心线程数20,最大线程数50

private final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(20, 50, 60, TimeUnit.SECONDS, workQueue);

public PushCallback(DeviceSubscribingHandlerImpl deviceSubscribingHandlerImpl,

DeviceReportHandlerImpl deviceReportHandlerImpl,

DeviceRawDataHandlerImpl deviceRawDataHandlerImpl) {

handlerMap.put("report", deviceReportHandlerImpl);

handlerMap.put("send", deviceSubscribingHandlerImpl);

handlerMap.put("raw_data_report", deviceRawDataHandlerImpl);

}

@Override

public void connectionLost(Throwable throwable) {

log.info("连接断开,重连");

if (client == null || !client.isConnected()) {

mqttConfig.getMqttPushClient();

}

}

@Override

public void messageArrived(String topic, MqttMessage mqttMessage) {

log.info("接收消息主题: {}", topic);

log.info("接收消息Qos: {}", mqttMessage.getQos());

log.info("接收消息内容: {}", new String(mqttMessage.getPayload()));

String extractedTopic = topic.substring(topic.lastIndexOf("/") + 1);

TopicHandlerService handler = handlerMap.get(extractedTopic);

threadPoolExecutor.submit(() -> {

try {

if (handler != null) {

handler.handleMessage(topic, mqttMessage);

} else {

log.warn("没有找到对应topic的处理程序: {}", topic);

}

} catch (Exception e) {

log.error("处理消息时出现异常:", e);

}

});

}

@Override

public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {

log.info("请求响应完成状态 -> {}", iMqttDeliveryToken.isComplete());

}

@PreDestroy

public void shutdown() {

threadPoolExecutor.shutdown(); // 关闭线程池

try {

if (!threadPoolExecutor.awaitTermination(60, TimeUnit.SECONDS)) {

threadPoolExecutor.shutdownNow(); // 超过时间强制关闭

}

} catch (InterruptedException ex) {

threadPoolExecutor.shutdownNow();

Thread.currentThread().interrupt();

}

}

}

--------------------------------------------------pom.xml

<!--mgtt-->

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-integration</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.integration</groupId>

<artifactId>spring-integration-stream</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.integration</groupId>

<artifactId>spring-integration-mqtt</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.integration</groupId>

<artifactId>spring-integration-core</artifactId>

</dependency>

<dependency>

<groupId>cn.hutool</groupId>

<artifactId>hutool-all</artifactId>

</dependency>

相关推荐
半盏茶香38 分钟前
在21世纪的我用C语言探寻世界本质 ——编译和链接(编译环境和运行环境)
c语言·开发语言·c++·算法
Evand J2 小时前
LOS/NLOS环境建模与三维TOA定位,MATLAB仿真程序,可自定义锚点数量和轨迹点长度
开发语言·matlab
LucianaiB2 小时前
探索CSDN博客数据:使用Python爬虫技术
开发语言·爬虫·python
Ronin3052 小时前
11.vector的介绍及模拟实现
开发语言·c++
计算机学长大白3 小时前
C中设计不允许继承的类的实现方法是什么?
c语言·开发语言
suweijie7683 小时前
SpringCloudAlibaba | Sentinel从基础到进阶
java·大数据·sentinel
公贵买其鹿4 小时前
List深拷贝后,数据还是被串改
java
PieroPc4 小时前
Python 写的 智慧记 进销存 辅助 程序 导入导出 excel 可打印
开发语言·python·excel
2401_857439696 小时前
SSM 架构下 Vue 电脑测评系统:为电脑性能评估赋能
开发语言·php
SoraLuna7 小时前
「Mac畅玩鸿蒙与硬件47」UI互动应用篇24 - 虚拟音乐控制台
开发语言·macos·ui·华为·harmonyos