通过工厂模式实现SpringBoot+MQTT-订阅与消费
1.pom.xml
<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>
2.yml配置
mqtt:
config:
username: admin
password: admin
hostUrl: tcp://xx.xx.xxx.xx:1883
clientId: emq-ss-client
defaultTopic: topic_default
timeout: 1000
keepalive: 60
enabled: false
3.MqttProperties
package com.rfos.assistsilkworm.mqtt.properties;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "mqtt.config")
public class MqttProperties {
@ApiModelProperty("用户名")
private String username;
@ApiModelProperty("密码")
private String password;
@ApiModelProperty("地址")
private String hostUrl;
@ApiModelProperty("客户端id")
private String clientId;
@ApiModelProperty("订阅主题")
private String defaultTopic;
@ApiModelProperty("超时时间")
private int timeout;
@ApiModelProperty("心跳")
private int keepalive;
@ApiModelProperty("mqtt开关")
private boolean enabled;
}
4.VO传输实体类
package com.rfos.assistsilkworm.mqtt.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class MqttVO {
@ApiModelProperty("订阅的主题")
public String topic ;
@ApiModelProperty("发送的内容")
public String payload ;
}
5.MqttReceiveHandle
package com.rfos.assistsilkworm.mqtt.handler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.integration.annotation.ServiceActivator;
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;
@Slf4j
@Component
public class MqttReceiveHandler implements MessageHandler {
@Override
@ServiceActivator(inputChannel = "MQTT_INPUT_CHANNEL")
public void handleMessage(Message<?> message) throws MessagingException {
log.info("收到订阅消息: {}", message);
String topic = message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC).toString();
log.info("消息主题:{}", topic);
}
}
6.MqttConfig
package com.rfos.assistsilkworm.mqtt.config;
import com.rfos.assistsilkworm.mqtt.handler.MqttReceiveHandler;
import com.rfos.assistsilkworm.mqtt.properties.MqttProperties;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.IntegrationComponentScan;
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.inbound.MqttPahoMessageDrivenChannelAdapter;
import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException;
import java.util.Arrays;
import java.util.List;
@Configuration
@IntegrationComponentScan
@Slf4j
public class MqttConfig {
@Autowired
private MqttProperties mqttProperties;
@Autowired
private MqttReceiveHandler mqttReceiveHandle;
@Bean(value = "getMqttConnectOptions")
public MqttConnectOptions getMqttConnectOptions() {
MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
mqttConnectOptions.setCleanSession(true);
mqttConnectOptions.setConnectionTimeout(10);
mqttConnectOptions.setAutomaticReconnect(true);
mqttConnectOptions.setUserName(mqttProperties.getUsername());
mqttConnectOptions.setPassword(mqttProperties.getPassword().toCharArray());
mqttConnectOptions.setServerURIs(new String[]{mqttProperties.getHostUrl()});
mqttConnectOptions.setKeepAliveInterval(10);
return mqttConnectOptions;
}
@Bean("mqttClientFactor")
public MqttPahoClientFactory mqttClientFactory() {
DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
factory.setConnectionOptions(getMqttConnectOptions());
return factory;
}
@Bean("MQTT_OUT_BOUND_CHANNEL")
public MessageChannel mqttOutboundChannel() {
return new DirectChannel();
}
@Bean
@ServiceActivator(inputChannel = "MQTT_OUT_BOUND_CHANNEL")
public MqttPahoMessageHandler mqttOutbound() {
MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler(mqttProperties.getClientId() + "_producer", mqttClientFactory());
messageHandler.setAsync(true);
messageHandler.setDefaultTopic(mqttProperties.getDefaultTopic());
messageHandler.setAsyncEvents(true);
DefaultPahoMessageConverter converter = new DefaultPahoMessageConverter();
converter.setPayloadAsBytes(true);
return messageHandler;
}
@Bean("inbound")
public MqttPahoMessageDrivenChannelAdapter inbound() {
List<String> topicList = Arrays.asList(mqttProperties.getDefaultTopic().trim().split(","));
String[] topics = new String[topicList.size()];
topicList.toArray(topics);
MqttPahoMessageDrivenChannelAdapter adapter =
new MqttPahoMessageDrivenChannelAdapter(mqttProperties.getClientId() + "_consumer", mqttClientFactory(), topics);
adapter.setCompletionTimeout(mqttProperties.getTimeout());
DefaultPahoMessageConverter converter = new DefaultPahoMessageConverter();
converter.setPayloadAsBytes(true);
adapter.setConverter(converter);
adapter.setQos(2);
adapter.setOutputChannel(mqttInputChannel());
return adapter;
}
@Bean("MQTT_INPUT_CHANNEL")
public MessageChannel mqttInputChannel() {
return new DirectChannel();
}
@Bean
@ServiceActivator(inputChannel = "MQTT_INPUT_CHANNEL")
public MessageHandler handler() {
return new MessageHandler() {
@Override
public void handleMessage(Message<?> message) throws MessagingException {
mqttReceiveHandle.handleMessage(message);
}
};
}
}
7.MqttPublishGateway
package com.rfos.assistsilkworm.mqtt.gateway;
import org.springframework.integration.annotation.MessageEndpoint;
import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Service;
@Service("mqttGateway")
@MessagingGateway(defaultRequestChannel = "MQTT_OUT_BOUND_CHANNEL")
public interface MqttPublishGateway {
void sendToMqttObject(@Header(MqttHeaders.TOPIC) String topic, byte[] payload);
void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, String payload);
void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.QOS) int qos, String payload);
void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, Object payload);
void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, byte[] payload);
}
8.MqttListener
package com.rfos.assistsilkworm.mqtt.listenter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.integration.mqtt.event.MqttConnectionFailedEvent;
import org.springframework.integration.mqtt.event.MqttMessageDeliveredEvent;
import org.springframework.integration.mqtt.event.MqttMessageSentEvent;
import org.springframework.integration.mqtt.event.MqttSubscribedEvent;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class MqttListener {
@EventListener(classes = MqttConnectionFailedEvent.class)
public void listenerAction(MqttConnectionFailedEvent mqttConnectionFailedEvent) {
log.info("连接失败的事件通知");
}
@EventListener(classes = MqttMessageSentEvent.class)
public void listenerAction(MqttMessageSentEvent mqttMessageSentEvent) {
log.info("已发送的事件通知[{}]",mqttMessageSentEvent.toString());
}
@EventListener(classes = MqttMessageDeliveredEvent.class)
public void listenerAction(MqttMessageDeliveredEvent mqttMessageDeliveredEvent) {
log.info("已传输完成的事件通知");
}
@EventListener(classes = MqttSubscribedEvent.class)
public void listenerAction(MqttSubscribedEvent mqttSubscribedEvent) {
log.info("消息订阅的事件通知");
log.info("成功订阅到主题: info={}", mqttSubscribedEvent.toString());
}
}
9.MqttClientController
package com.rfos.assistsilkworm.mqtt.client;
import com.rfos.assistsilkworm.common.CommonResult;
import com.rfos.assistsilkworm.mqtt.config.MqttConfig;
import com.rfos.assistsilkworm.mqtt.gateway.MqttPublishGateway;
import org.eclipse.paho.client.mqttv3.IMqttClient;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.core.MessageProducer;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/mqtt")
public class MqttClientController {
@Autowired
private MqttPublishGateway mqttPublishGateway;
@Autowired
@Qualifier("inbound")
private MqttPahoMessageDrivenChannelAdapter messageProducer;
@GetMapping("/testPublish")
public CommonResult sentTest(@RequestParam("topic") String topic,
@RequestParam("payload") String payload){
mqttPublishGateway.sendToMqtt(topic,1,payload);
return CommonResult.success();
}
@GetMapping("/testSubscribe")
@ServiceActivator(inputChannel = "MQTT_INPUT_CHANNEL")
public CommonResult testSubscribe() throws MqttException {
messageProducer.addTopic("TOPICS");
return CommonResult.success();
}
}