import lombok.Data;
import java.io.Serializable;
/**
* 基础MQTT配置
*/
@Data
public class BaseMqttConfig implements Serializable {
private static final long serialVersionUID = -4049488718513019015L;
/**
* 是否开启
*/
public Boolean enable = false;
/**
* 订阅地址可设置多个
*/
public String hostUrls;
/**
* MQTT账号
*/
public String hostName;
/**
* MQTT密码
*/
public String password;
/**
* 客户端ID
*/
public String clientId;
/**
* 主题
*/
public String topics;
/**
* 超时时间 单位为秒
*/
public Integer timeout = 10;
/**
* 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送心跳判断客户端是否在线
*/
public Integer keepAlive = 30;
/**
* 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息)
*/
public Boolean clearSession = false;
/**
* “遗嘱”消息的话题
*/
public String willTopic = "offline";
}
power:
mqtt:
charge:
enable: true
hostUrls: tcp://test.test.com:2354
hostName: test
password: test
clientId: mqtt_server
topics: test/power/n/up/#
timeout: 10
keepAlive: 60
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.channel.ExecutorChannel;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.IntegrationFlows;
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.MessageChannel;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import javax.annotation.Resource;
@Configuration
@ConditionalOnProperty(name = "power.mqtt.charge.enable", havingValue = "true")
public class PowerMqttServer extends BaseMqttServer {
@Resource
private PowerMqttConfig config;
@Resource
@Qualifier(ThreadPoolConfig.COMMON_THREAD_POOL)
private ThreadPoolTaskExecutor executor;
@Resource
private PowerMessageHandler messageHandle;
/**
* 客户端工厂
*
* @return
*/
@Bean
public MqttPahoClientFactory initializeMqttFactory() {
try {
DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
MqttConnectOptions options = new MqttConnectOptions();
options.setServerURIs(config.hostUrls.split(",")); // 设置代理端的URL地址,可以是多个
options.setUserName(config.hostName); // 设置连接的用户名
options.setPassword(config.password.toCharArray()); // 设置连接的密码
options.setConnectionTimeout(config.timeout);// 设置超时时间 单位为秒
options.setKeepAliveInterval(config.keepAlive);// 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送心跳判断客户端是否在线 但这个方法并没有重连的机制
options.setWill("willTopic", config.willTopic.getBytes(), 2, false);// 设置“遗嘱”消息的话题,若客户端与服务器之间的连接意外中断,服务器将发布客户端的“遗嘱”消息。
factory.setConnectionOptions(options);
AssertLog.info("\n\n\t\t\t\t\t\t\t\t======hostUrl:{}======MQTT已建立连接,hostName:{}======\n", config.hostUrls, config.hostName);
return factory;
} catch (Exception e) {
AssertLog.error("=======MQTT建立失败======", e.getCause());
}
return new DefaultMqttPahoClientFactory();
}
/**
* 入站消息管道
*
* @return
*/
@Bean
public MessageChannel mqttInboundChannel() {
AssertLog.info("==============MQTT入站消息管道加载成功==============");
return new ExecutorChannel(executor);// 用线程池
}
/**
* Mqtt 管道适配器
*
* @return
*/
@Bean
public MqttPahoMessageDrivenChannelAdapter adapter(MqttPahoClientFactory factory) {
String inClientId = config.clientId + MqttConstant.CLIENT_NAME_IN;
MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(inClientId, factory, config.topics.split(","));
adapter.setCompletionTimeout(5000);
adapter.setQos(2);
DefaultPahoMessageConverter converter = new DefaultPahoMessageConverter();
converter.setPayloadAsBytes(true);
adapter.setConverter(converter);
return adapter;
}
/**
* 消息消费者 (接收,处理来自mqtt的消息)
*
* @param adapter
* @return
*/
@Bean
public IntegrationFlow mqttInbound(MqttPahoMessageDrivenChannelAdapter adapter) {
return IntegrationFlows.from(adapter)
.channel(new ExecutorChannel(executor))
.handle(messageHandle)
.get();
}
/**
* 出站处理器 (向 mqtt 发送消息 生产者)
*
* @param factory
* @return
*/
@Bean
public IntegrationFlow mqttOutboundFlow(MqttPahoClientFactory factory) {
AssertLog.info("==============MQTT出站消息管道加载成功==============");
String outClientId = config.clientId + MqttConstant.CLIENT_NAME_OUT;
MqttPahoMessageHandler handler = new MqttPahoMessageHandler(outClientId, factory);
handler.setAsync(true); // 如果设置成true,即异步,发送消息时将不会阻塞。
DefaultPahoMessageConverter converter = new DefaultPahoMessageConverter();//设置转换器 发送bytes数据
converter.setPayloadAsBytes(true);
handler.setDefaultTopic(config.topics.split(",")[0]);
return IntegrationFlows.from(MqttConstant.CHANNEL_NAME_OUT).handle(handler).get();
}
}
@Component
public class PowerMessageHandler implements MessageHandler {
@Override
public void handleMessage(Message<?> message) throws MessagingException {
String topic = (String) message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC);
}
}
import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
@Component
@MessagingGateway(defaultRequestChannel = MqttConstant.CHANNEL_NAME_OUT)
public interface MqttSendService {
/**
* 指定topic进行消息发送
*
* @param topic
* @param payload
*/
void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, String payload);
/**
* 指定topic进行消息发送
*
* @param topic
* @param qos
* @param payload
*/
void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.QOS) Integer qos, String payload);
/**
* 指定topic进行消息发送
*
* @param topic
* @param qos
* @param payload
*/
void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.QOS) Integer qos, byte[] payload);
}
import java.lang.management.ManagementFactory;
/**
* MQTT基本参数
*/
public class MqttConstant {
/**
* 出站-生产者
*/
public static final String CHANNEL_NAME_OUT = "mqttOutboundChannel";
/**
* 入站-消费者
*/
public static final String CHANNEL_NAME_IN = "mqttInputChannel";
/**
* 出站客户端ID
*/
public static final String CLIENT_NAME_OUT = "_publish_" + ManagementFactory.getRuntimeMXBean().getName();
;
/**
* 入站客户端ID
*/
public static final String CLIENT_NAME_IN = "_subscribe_" + ManagementFactory.getRuntimeMXBean().getName();
}