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

相关推荐
陌小呆^O^5 分钟前
Cmakelist.txt之win-c-udp-server
c语言·开发语言·udp
计算机毕设指导611 分钟前
基于 SpringBoot 的作业管理系统【附源码】
java·vue.js·spring boot·后端·mysql·spring·intellij-idea
Gu Gu Study12 分钟前
枚举与lambda表达式,枚举实现单例模式为什么是安全的,lambda表达式与函数式接口的小九九~
java·开发语言
Chris _data15 分钟前
二叉树oj题解析
java·数据结构
牙牙70520 分钟前
Centos7安装Jenkins脚本一键部署
java·servlet·jenkins
时光の尘27 分钟前
C语言菜鸟入门·关键字·float以及double的用法
运维·服务器·c语言·开发语言·stm32·单片机·c
paopaokaka_luck28 分钟前
[371]基于springboot的高校实习管理系统
java·spring boot·后端
以后不吃煲仔饭41 分钟前
Java基础夯实——2.7 线程上下文切换
java·开发语言
进阶的架构师41 分钟前
2024年Java面试题及答案整理(1000+面试题附答案解析)
java·开发语言
前端拾光者1 小时前
利用D3.js实现数据可视化的简单示例
开发语言·javascript·信息可视化