集成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>

相关推荐
m0_748245342 分钟前
python——Django 框架
开发语言·python·django
曼巴UE57 分钟前
UE5.3 C++ TArray系列(一)
开发语言·c++·ue5
熬夜苦读学习18 分钟前
Linux文件系统
linux·运维·服务器·开发语言·后端
菜鸟一枚在这26 分钟前
深度解析建造者模式:复杂对象构建的优雅之道
java·开发语言·算法
gyeolhada44 分钟前
2025蓝桥杯JAVA编程题练习Day5
java·数据结构·算法·蓝桥杯
阿巴~阿巴~1 小时前
多源 BFS 算法详解:从原理到实现,高效解决多源最短路问题
开发语言·数据结构·c++·算法·宽度优先
菜鸟一枚在这1 小时前
深入理解设计模式之代理模式
java·设计模式·代理模式
小天努力学java1 小时前
【面试系列】Java开发--AI常见面试题
java·人工智能·面试
river661 小时前
java开发——为什么要使用动态代理?
java
Zayn~1 小时前
JVM系列--虚拟机类加载机制
java