一: pom文件添加依赖
<!-- mqtt -->
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-mqtt</artifactId>
</dependency>
二: yml配置文件添加MQTT配置信息
###################### MQTT #################################
mqtt:
# 服务器地址
host: tcp://127.0.0.1:1883
# ID唯一
clientId: MQTT_WK
# 主题 多个主题用逗号(,)分割 #表示这个主题下面所有
topics: topic1,topic2,topic2/topic22/#
# 用户名
username: admin
# 密码
password: 1q2w3e4r.
# 连接超时
timeout: 30
# 心跳检测
keepalive: 60
# 对消息处理的几种机制。
# 0 表示的是订阅者没收到消息不会再次发送,消息会丢失
# 1 表示的是会尝试重试,一直到接收到消息,但这种情况可能导致订阅者收到多次重复消息
# 2 多了一次去重的动作,确保订阅者收到的消息有一次
qos: 1
# false为建立持久会话
cleanSession: false
# 断开后重新连接
automaticReconnect: true
三: 新建一个接收MQTT消息的实体用于接收参数(@RequestBody), 也可以直接参数字段(@RequestParam)这一步就不需要了
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @Description 消息实体对象
* @Author WangKun
* @Date 2023/4/19 14:59
* @Version
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MQTTMessage implements Serializable {
/**
* MQTT主题
*/
private String topic;
/**
* qos
*/
private Integer qos = 1;
/**
* MQTT内容
*/
private String content;
}
四: 新建一个MQTT配置类(这可以改造两个配置类,一个生产者一个消费者,yml配置文件也是一个生产者一个消费者)
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @Description MQTT的配置类
* @Author WangKun
* @Date 2023/4/19 10:38
* @Version
*/
@Component
@Data
public class MQTTConfig {
/**
* host 服务器地址配置
*/
@Value("${mqtt.host}")
private String[] host;
/**
* clientId
*/
@Value("${mqtt.clientId}")
private String clientId;
/**
* 主题
*/
@Value("${mqtt.topics}")
private String[] topics;
/**
* 用户名
*/
@Value("${mqtt.username}")
private String username;
/**
* 密码
*/
@Value("${mqtt.password}")
private String password;
/**
* 连接超时时长
*/
@Value("${mqtt.timeout}")
private Integer timeout;
/**
* keep Alive时间(心跳检测)
*/
@Value("${mqtt.keepalive}")
private Integer keepalive;
/**
* 遗嘱消息 QoS
*/
@Value("${mqtt.qos}")
private Integer qos;
/**
* false为建立持久会话
*/
@Value("${mqtt.cleanSession}")
private Boolean cleanSession;
/**
* 断开后重新连接
*/
@Value("${mqtt.automaticReconnect}")
private Boolean automaticReconnect;
}
五: 新建生产者与消费者
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import javax.annotation.Resource;
/**
* @Description MQTT生产端配置
* @Author WangKun
* @Date 2023/4/19 14:58
* @Version
*/
@Configuration
public class MQTTProduceConfig {
@Resource
private MQTTConfig mqttConfig;
// 客户端与服务器之间的连接意外中断,服务器将发布客户端的“遗嘱”消息
private static final byte[] WILL_DATA;
static {
WILL_DATA = "offline".getBytes();
}
/**
* @param
* @Description 出站直连通道
* @Throws
* @Return org.springframework.messaging.MessageChannel
* @Date 2023-04-20 15:15:42
* @Author WangKun
*/
@Bean("mqttOut")
public MessageChannel mqttOutBoundChannel() {
return new DirectChannel();
}
/**
* @param
* @Description 创建MqttPahoClientFactory 设置MQTT的broker的连接属性
* @Throws
* @Return org.springframework.integration.mqtt.core.MqttPahoClientFactory
* @Date 2023-04-20 15:15:52
* @Author WangKun
*/
@Bean
public MqttPahoClientFactory outClientFactory() {
DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
String[] hosts = mqttConfig.getHost();
MqttConnectOptions options = new MqttConnectOptions();
options.setServerURIs(hosts);
options.setUserName(mqttConfig.getUsername());
options.setPassword(mqttConfig.getPassword().toCharArray());
options.setConnectionTimeout(mqttConfig.getTimeout());
options.setKeepAliveInterval(mqttConfig.getKeepalive());
options.setCleanSession(mqttConfig.getCleanSession());
options.setAutomaticReconnect(mqttConfig.getAutomaticReconnect());
options.setWill("willTopic", WILL_DATA, 2, false);
factory.setConnectionOptions(options);
return factory;
}
/**
* @param
* @Description 出站
* @Throws
* @Return org.springframework.messaging.MessageHandler
* @Date 2023-04-20 15:16:05
* @Author WangKun
*/
@Bean
@ServiceActivator(inputChannel = "mqttOut")
public MessageHandler mqttOutbound() {
MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler(mqttConfig.getClientId() + "_producer", outClientFactory());
//如果设置成true,即异步,发送消息时将不会阻塞。
messageHandler.setAsync(true);
//设置默认QoS
messageHandler.setDefaultQos(mqttConfig.getQos());
DefaultPahoMessageConverter defaultPahoMessageConverter = new DefaultPahoMessageConverter();
//发送默认按字节类型发送消息
// defaultPahoMessageConverter.setPayloadAsBytes(true);
messageHandler.setConverter(defaultPahoMessageConverter);
return messageHandler;
}
}
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.core.MessageProducer;
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import javax.annotation.Resource;
/**
* @Description MQTT 消费端的配置
* @Author WangKun
* @Date 2023/4/19 14:56
* @Version
*/
@Configuration
@Slf4j
public class MQTTConsumeConfig {
@Resource
private MQTTConfig mqttConfig;
@Resource
private MQTTMessageHandler mqttMessageHandler;
// 客户端与服务器之间的连接意外中断,服务器将发布客户端的“遗嘱”消息
private static final byte[] WILL_DATA;
static {
WILL_DATA = "offline".getBytes();
}
/**
* @param
* @Description 入站直连通道
* @Throws
* @Return org.springframework.messaging.MessageChannel
* @Date 2023-04-20 15:10:25
* @Author WangKun
*/
@Bean("mqttInput")
public MessageChannel mqttInputChannel() {
return new DirectChannel();
}
/**
* @param
* @Description 创建MqttPahoClientFactory 设置MQTT的broker的连接属性
* @Throws
* @Return org.springframework.integration.mqtt.core.MqttPahoClientFactory
* @Date 2023-04-20 15:11:33
* @Author WangKun
*/
@Bean
public MqttPahoClientFactory inClientFactory() {
DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
MqttConnectOptions options = new MqttConnectOptions();
options.setServerURIs(mqttConfig.getHost());
options.setUserName(mqttConfig.getUsername());
options.setPassword(mqttConfig.getPassword().toCharArray());
options.setConnectionTimeout(mqttConfig.getTimeout());
options.setKeepAliveInterval(mqttConfig.getKeepalive());
options.setCleanSession(mqttConfig.getCleanSession());
options.setAutomaticReconnect(mqttConfig.getAutomaticReconnect());
options.setWill("willTopic", WILL_DATA, 2, false);
factory.setConnectionOptions(options);
return factory;
}
/**
* @param
* @Description 入站
* @Throws
* @Return org.springframework.integration.core.MessageProducer
* @Date 2023-04-20 15:12:06
* @Author WangKun
*/
@Bean
public MessageProducer producer() {
MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(mqttConfig.getClientId() + "_customer", inClientFactory(), mqttConfig.getTopics());
adapter.setCompletionTimeout(5000);
DefaultPahoMessageConverter defaultPahoMessageConverter = new DefaultPahoMessageConverter();
// 按字节接收消息
// defaultPahoMessageConverter.setPayloadAsBytes(true);
adapter.setConverter(defaultPahoMessageConverter);
adapter.setQos(mqttConfig.getQos());
adapter.setOutputChannel(mqttInputChannel());
return adapter;
}
/**
* @param
* @Description 通过通道获取数据
* ServiceActivator注解表明:当前方法用于处理MQTT消息,inputChannel参数指定了用于消费消息的channel。
* tips:
* 异步处理
* @Throws
* @Return org.springframework.messaging.MessageHandler
* @Date 2023-04-20 15:12:55
* @Author WangKun
*/
@Bean
@ServiceActivator(inputChannel = "mqttInput")
public MessageHandler handler() {
return this.mqttMessageHandler;
}
}
六: 重写MQTT网关接口
import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.handler.annotation.Header;
/**
* @Description 网关接口MqttGateway
* @Author WangKun
* @Date 2023/4/19 15:01
* @Version
*/
@MessagingGateway(defaultRequestChannel = "mqttOut")
public interface MQTTGateway {
/**
* @param message 消息
* @Description 定义重载方法,用于消息发送
* @Throws
* @Return void
* @Date 2023-04-20 16:53:22
* @Author WangKun
*/
void sendToMqtt(String message);
/**
* @param topic 主题
* @param message 消息
* @Description 指定topic进行消息发送
* @Throws
* @Return void
* @Date 2023-04-20 16:54:03
* @Author WangKun
*/
void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, String message);
/**
* @param topic 主题
* @param qos qos
* @param message 消息
* @Description 指定topic和qos进行消息发送
* @Throws
* @Return void
* @Date 2023-04-20 16:54:33
* @Author WangKun
*/
void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.QOS) int qos, String message);
/**
* @param topic 主题
* @param qos qos
* @param message 消息(字节数字类型)
* @Description 指定topic和qos进行消息发送
* @Throws
* @Return void
* @Date 2023-04-20 16:54:56
* @Author WangKun
*/
void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.QOS) int qos, byte[] message);
}
七: 消费端消息拦截提取
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException;
import org.springframework.stereotype.Component;
/**
* @Description 消费端消息处理工具(消费端消息处理)
* @Author WangKun
* @Date 2023/4/20 15:31
* @Version
*/
@AllArgsConstructor
@Component
@Slf4j
public class MQTTMessageHandler implements MessageHandler {
/**
* @Description 消息处理(在这实现接收消息处理业务, 资源注入不进来,可以手动注入)
* @param message
* @Throws
* @Return void
* @Date 2023-04-20 15:38:22
* @Author WangKun
*/
@Override
public void handleMessage(Message<?> message) throws MessagingException {
log.info("收到的完整消息为--->{}", message);
log.info("----------------------");
log.info("message:" + message.getPayload());
log.info("Id:" + message.getHeaders().getId());
log.info("receivedQos:" + message.getHeaders().get(MqttHeaders.RECEIVED_QOS));
String topic = (String) message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC);
log.info("topic:" + topic);
log.info("----------------------");
}
}
八: 为了方便使用,再封装发送工具
import org.springframework.stereotype.Component;
/**
* @Description MQTT 消息发送工具类
* @Author WangKun
* @Date 2023/4/20 16:13
* @Version
*/
@Component
public class MQTTUtils {
/**
* 资源手动注入
*/
private static final MQTTGateway mqttGateway = SpringUtils.getBean(MQTTGateway.class);
/**
* @param message 消息
* @Description 定义重载方法,用于消息发送
* @Throws
* @Return void
* @Date 2023-04-20 16:53:22
* @Author WangKun
*/
public static void send(String message) {
mqttGateway.sendToMqtt(message);
}
/**
* @param topic 主题
* @param message 消息
* @Description 指定topic进行消息发送
* @Throws
* @Return void
* @Date 2023-04-20 16:54:03
* @Author WangKun
*/
public static void send(String topic, String message) {
mqttGateway.sendToMqtt(topic, message);
}
/**
* @param topic 主题
* @param qos qos
* @param message 消息
* @Description 指定topic和qos进行消息发送
* @Throws
* @Return void
* @Date 2023-04-20 16:54:33
* @Author WangKun
*/
public static void send(String topic, int qos, String message) {
mqttGateway.sendToMqtt(topic, qos, message);
}
/**
* @param topic 主题
* @param qos qos
* @param message 消息(字节数字类型)
* @Description 指定topic和qos进行消息发送
* @Throws
* @Return void
* @Date 2023-04-20 16:54:56
* @Author WangKun
*/
public static void send(String topic, int qos, byte[] message) {
mqttGateway.sendToMqtt(topic, qos, message);
}
}
九: 测试类
/**
* @Description TODO
* @Author WangKun
* @Date 2023/4/20 16:58
* @Version
*/
@RestController
public class MQTTController {
@PostMapping("/send")
public String send(@RequestBody MQTTMessage message) {
// 发送消息到指定主题
// mqttGateWay.sendToMqtt(myMessage.getTopic(), 1, myMessage.getContent());
MQTTUtils.send(message.getTopic(), message.getQos(), message.getContent());
return "send topic: " + message.getTopic() + ", message : " + message.getContent();
}
}
整体代码结构
测试结果:
EMQX服务监控:
Apifox:
MQTTX订阅该主题同时也收到消息
MQTTX发送消息到该主题
版权归原作者 掐指一算乀缺钱 所有, 如有侵权,请联系我们删除。