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

相关推荐
运器12317 分钟前
【一起来学AI大模型】算法核心:数组/哈希表/树/排序/动态规划(LeetCode精练)
开发语言·人工智能·python·算法·ai·散列表·ai编程
岁忧18 分钟前
(LeetCode 每日一题) 1865. 找出和为指定值的下标对 (哈希表)
java·c++·算法·leetcode·go·散列表
YuTaoShao21 分钟前
【LeetCode 热题 100】240. 搜索二维矩阵 II——排除法
java·算法·leetcode
whoarethenext33 分钟前
使用 C++ 实现 MFCC 特征提取与说话人识别系统
开发语言·c++·语音识别·mfcc
ITfeib43 分钟前
Flutter
开发语言·javascript·flutter
考虑考虑1 小时前
JDK9中的dropWhile
java·后端·java ee
想躺平的咸鱼干1 小时前
Volatile解决指令重排和单例模式
java·开发语言·单例模式·线程·并发编程
Owen_Q2 小时前
Denso Create Programming Contest 2025(AtCoder Beginner Contest 413)
开发语言·算法·职场和发展
hqxstudying2 小时前
java依赖注入方法
java·spring·log4j·ioc·依赖
·云扬·2 小时前
【Java源码阅读系列37】深度解读Java BufferedReader 源码
java·开发语言