Springboot+MQTT集成,解决Callback中不能发布消息问题

Springboot+MQTT集成

pom文件

<dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</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.boot</groupId>
            <artifactId>spring-boot-starter-integration</artifactId>
        </dependency>
    </dependencies>

yml文件

mqtt:
  host: tcp://192.188.1.1:1883
  username: admin
  password: public
  timeout: 30 #连接超时
  keepalive: 60  #心跳检查时间
  clientid: client01
  topic: test01/#
MqttCallbackAutoConfiguration.java
@Configuration
@EnableConfigurationProperties(MqttConfig.class)
@ConditionalOnBean(MqttPushClient.class)
@ConditionalOnProperty(prefix = "mqtt", value = "enabled", matchIfMissing = true)
public class MqttCallbackAutoConfiguration {
    @Autowired
    private MqttConfig properties;
    @Autowired
    private MqttPushClient mqttPushClient;

    @Bean
    @ConditionalOnMissingBean(PushCallback.class)
    public PushCallback pushCallback() {
        PushCallback pushCallback = new PushCallback(properties);
        mqttPushClient.setPushCallback(pushCallback);

        mqttPushClient.connect(properties.getHost(), properties.getClientid(), properties.getUsername(), properties.getPassword(), properties.getTimeout(),properties.getKeepalive());
        mqttPushClient.subscribe(properties.getTopic(), 0);

        return pushCallback;
    }
}
MqttConfig.java
@Data
@ConfigurationProperties(MqttConfig.PREFIX)
public class MqttConfig {
    public static final  String PREFIX="mqtt";
    private String host;
    private String clientid;
    private String username;
    private String password;
    private String topic;
    private int timeout;
    private int keepalive;
}
MqttPushClient.java
@Slf4j
@Component
public class MqttPushClient {
    private PushCallback pushCallback;

    private static MqttClient client;

    public  static MqttClient getClient(){
        return  client;
    }

    public static void setClient(MqttClient client){
        MqttPushClient.client = client;
    }

    public void setPushCallback(PushCallback pushCallback) {
        this.pushCallback = pushCallback;
    }

    /**
     * 客户端连接
     *
     * @param host      ip+端口
     * @param clientID  客户端Id
     * @param username  用户名
     * @param password  密码
     * @param timeout   超时时间
     * @param keeplive 保留数
     */
    public void connect(String host,String clientID,String username,String password,int timeout,int keeplive){
        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(keeplive);
            options.setAutomaticReconnect(true);
            MqttPushClient.setClient(client);
            try {
                client.setCallback(pushCallback);
                client.connect(options);
            }catch (Exception e){
                e.printStackTrace();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 发布,默认qos为0,非持久化
     * @param topic
     * @param pushMessage
     */
    public void publish(int qos, boolean retained, String topic,String pushMessage){
        try {
            MqttMessage message = new MqttMessage();
            message.setPayload(pushMessage.getBytes(StandardCharsets.UTF_8));
            message.setRetained(retained);
            message.setQos(qos);
            client.publish(topic, message);
        }
        catch (Exception e) {
            log.error(e.getMessage());
        }
    }


    /**
     * 订阅某个主题,qos默认为0
     * @param topic
     */
    public void subscribe(String topic){
        log.info("开始订阅主题" + topic);
        subscribe(topic,0);
    }

    public void subscribe(String topic, int qos){
        try {
            MqttPushClient.getClient().subscribe(topic,qos);
        }catch (MqttException e){
            e.printStackTrace();
        }
    }
}
PushCallback.java
@Slf4j
public class PushCallback implements MqttCallback {
    private MqttConfig mqttConfig;
    @Autowired
    private IMqttResponse mqttResponse;
    @Autowired
    MqttPushClient mqttPushClient;
    @Autowired
    QuartzScheduler quartzScheduler;

    public PushCallback(MqttConfig mqttConfiguration) {
        this.mqttConfig = mqttConfiguration;
    }

    @Override
    public void connectionLost(Throwable throwable) {
        log.info("连接断开,正在重连....");
        if (MqttPushClient.getClient() == null || !MqttPushClient.getClient().isConnected()) {
            log.info("连接断开,正在重连....");
            //mqttPushClient.;
        }
    }

    @Override
    public void messageArrived(String topic, MqttMessage message) throws Exception {
        log.info("接收消息主题 : " + topic);
        //log.info("接收消息Qos : " + message.getQos());
        //log.info("接收消息内容 : " + new String(message.getPayload()));

        String[] topics = topic.split("/");
        if(topics.length == 3) {
            if(topics[1].equals(mqttConfig.getPlattopic())) {

                String topicResp = "response-topic";
                String str = "get string";
                mqttPushClient.pushlish(0, false, topicResp, str);
        }
    }

    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {
        try {
            log.info("deliveryComplete---------" + token.getTopics());
        }
        catch (Exception e) {
            log.error(e.getMessage());
        }
    }
}

 完毕,代码可以跑起来了。

但是运行起来发现有点问题,用MQTTBox发送个消息后,PushCallback的messageArrived接收到消息开始处理,执行到mqttPushClient.pushlish就不往下走了,程序挂死在这儿了。

messageArrived方法由MQTT客户机同步调用。直到该方法干净地返回时,才将确认发送回服务器。

如果该方法的实现抛出异常,那么客户端将被关闭。当客户机下一次重新连接时,服务器将重新发送任何QoS 1或2消息。

当此方法的实现运行时到达的任何附加消息都将在内存中构建,然后在网络上备份。

如果应用程序需要持久化数据,那么它应该确保数据在从这个方法返回之前被持久化,就像从这个方法返回之后,消息被认为已经被传递了,并且不会被复制。

可以在这个回调的实现中发送一个新的消息(例如,对这个消息的响应),但是实现不能断开客户端,因为要发送对正在处理的消息的确认是不可能的,并且会出现死锁。

就是每次回调只能在上次回调完成后才能进入这个方法。如果时间多长,mqtt服务器会接不到消息,认为服务挂掉,断开连接。所有这个方法中如果有耗时的操作应该另外加一个线程操作。
 

解决Callback中不能发布消息问题

修改一下发送消息的地方,修改MqttPushClient类的publish方法

public void publish(int qos, boolean retained, String topic,String pushMessage){
        try {
            MqttMessage message = new MqttMessage();
            message.setPayload(pushMessage.getBytes(StandardCharsets.UTF_8));
            message.setRetained(retained);
            message.setQos(qos);
            //client.publish(topic, message);

            MqttDeliveryToken token;
            MqttTopic mqttTopic = client.getTopic(topic);
            token = mqttTopic.publish(message);
        }
        catch (Exception e) {
            log.error(e.getMessage());
        }
    }

问题解决!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值