mqtt动态订阅。动态增加订阅,过期自动取消订阅

mqtt动态订阅。动态增加订阅,过期自动取消订阅

1.通过controller 测试 动态增加订阅 和发送消息

package com.example.demo.mqtt.local;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
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;

import javax.annotation.Resource;

@RestController
@RequestMapping("/mqtt")
@Slf4j
public class Test1 {

    @Resource
    LocalMqttService localMqttService;

    @Resource
    LocalMqttSendService localMqttSendService;

    @GetMapping("/add")
    public  void  addTopic(@RequestParam("topic") String topic){
        localMqttService.addTopic(topic,0);
    }

    @GetMapping("/send")
    public  void  send(@RequestParam("topic") String topic){
        JSONObject jsonObject=new JSONObject();
        jsonObject.put("time",System.currentTimeMillis());
        jsonObject.put("topic",topic);
        localMqttSendService.sendToMqtt(topic,0,jsonObject.toJSONString());
        log.info(jsonObject.toJSONString());
    }

}

2.mqtt的配置类

package com.example.demo.mqtt.local;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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.outbound.MqttPahoMessageHandler;
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;

@Configuration
public class LocalMqttConfig {
    //订阅通道的bean名称
    public static final String CHANNEL_NAME_IN = "LocalMqttInboundChannel";
    //发布通道的bean名称
    public static final String CHANNEL_NAME_OUT = "LocalMqttOutboundChannel";
    public static final String PRODUCER_MESSAGE_HANDLE = "LocalMqttMessageHandler";
    //消费者的bean名称
    public static final String CONSUMER_NAME = "LocalMqttConsumer";
    //消费者处理handler的bean名称
    public static final String CONSUMER_HANDLER_NAME = "LocalMqttHandler";
    public static final String PRODUCER_NAME = "LocalMqttProducer";

    @Value("${mqtt.local.username}")
    private String username;

    @Value("${mqtt.local.password}")
    private String password;

    @Value("${mqtt.local.url}")
    private String url;

    @Value("${mqtt.local.producerClientId}")
    private String producerClientId;

    @Value("${mqtt.local.consumerClientId}")
    private String consumerClientId;

    @Value("${mqtt.local.consumerTopic}")
    private String consumerTopic;

    @Autowired
    private LocalMqttReceiveService mqttReceiveService;

    /**
     * MQTT连接器选项
     *
     * @return {@link MqttConnectOptions}
     */
    public MqttConnectOptions getMqttConnectOptions() {
        MqttConnectOptions options = new MqttConnectOptions();
        // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,
        // 这里设置为true表示每次连接到服务器都以新的身份连接
        options.setCleanSession(true);
        // 设置连接的用户名
        options.setUserName(username);
        // 设置连接的密码
        options.setPassword(password.toCharArray());
        // 设置连接地址,多个用“,”隔开
        options.setServerURIs(StringUtils.split(url, ","));
        // 设置超时时间 单位为秒
        options.setConnectionTimeout(10);
        // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送心跳判断客户端是否在线,但这个方法并没有重连的机制
        options.setKeepAliveInterval(20);
        // 设置“遗嘱”消息的话题,若客户端与服务器之间的连接意外中断,服务器将发布客户端的“遗嘱”消息。
        //options.setWill("willTopic", WILL_DATA, 2, false);
        return options;
    }

    /**
     * MQTT客户端
     *
     * @return {@link MqttPahoClientFactory}
     */
    public MqttPahoClientFactory mqttClientFactory() {
        DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
        factory.setConnectionOptions(getMqttConnectOptions());
        return factory;
    }

    /**
     * MQTT信息通道(生产者)
     *
     * @return {@link MessageChannel}
     */
    @Bean(name = CHANNEL_NAME_OUT)
    public MessageChannel mqttOutboundChannel() {
        return new DirectChannel();
    }

    /**
     * MQTT消息处理器(生产者)
     *
     * @return {@link MessageHandler}
     */
    @Bean(name = PRODUCER_MESSAGE_HANDLE)
    @ServiceActivator(inputChannel = CHANNEL_NAME_OUT)
    public MessageHandler mqttOutbound() {
        String cid = producerClientId + "UUIDGenerator.getUUID16()";
        MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler(
                cid,
                mqttClientFactory());
        messageHandler.setAsync(true);
        return messageHandler;
    }

    /**
     * MQTT消息订阅绑定(消费者)
     *
     * @return {@link MessageProducer}
     */
    @Bean(name = CONSUMER_NAME)
    public MqttPahoMessageDrivenChannelAdapter inbound() {
        String[] topics = StringUtils.split(consumerTopic, ",");
        String cid = consumerClientId + "UUIDGenerator.getUUID16()";
        // 可以同时消费(订阅)多个Topic
        MqttPahoMessageDrivenChannelAdapter adapter =
                new MqttPahoMessageDrivenChannelAdapter(
                        cid, mqttClientFactory(), topics);
        DefaultPahoMessageConverter converter = new DefaultPahoMessageConverter();
        converter.setPayloadAsBytes(true);
        adapter.setConverter(converter);
        adapter.setQos(0);
        // 设置订阅通道
        adapter.setOutputChannel(mqttInboundChannel());
        return adapter;
    }

    /**
     * MQTT信息通道(消费者)
     *
     * @return {@link MessageChannel}
     */
    @Bean(name = CHANNEL_NAME_IN)
    public MessageChannel mqttInboundChannel() {
        return new DirectChannel();
    }

    /**
     * MQTT消息处理器(消费者)
     *
     * @return {@link MessageHandler}
     */
    @Bean(name = CONSUMER_HANDLER_NAME)
    @ServiceActivator(inputChannel = CHANNEL_NAME_IN)
    public MessageHandler handler() {
        return message -> mqttReceiveService.receiveNotification(message);
    }
}

3.mqtt的消息处理器

@Component
@Slf4j
public class LocalMqttReceiveService {
  public void receiveNotification(Message<?> message) {

        Optional.ofNullable(message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC))
                .map(Objects::toString)
                .ifPresent(log::error);
           }
}

4.通过通道适配器动态订阅topic
通过定时任务 取消订阅

@Service
@Slf4j
public class LocalMqttService {
    @Resource
    private LocalMqttSendService localMqttSendService;
    @Resource(name = LocalMqttConfig.CONSUMER_NAME)
    private MqttPahoMessageDrivenChannelAdapter mqttPahoMessageDrivenChannelAdapter;
    
    private final Map<String, Long> topicMap = new ConcurrentHashMap<>();

    public void addTopic(String topic,int qos) {
        if (!topicMap.containsKey(topic)) {
            mqttPahoMessageDrivenChannelAdapter.addTopic(topic, qos);
        }
        topicMap.put(topic, System.currentTimeMillis());
    }

    public void sendMessage(String topic, int qos, String payload) {
        localMqttSendService.sendToMqtt(topic, qos, payload);
    }

    public void sendMessage(String topic, int qos, byte[] payload) {
        localMqttSendService.sendToMqtt(topic, qos, payload);
    }

    /**
     * 过期队列,超过时间,则取消订阅topic
     */
    @Scheduled(fixedRate = 60000)
    public void scheduledTask() {
        if (!topicMap.isEmpty()) {
            long baseLine = System.currentTimeMillis() - 300000;
            Iterator<Map.Entry<String,Long>> iterable = topicMap.entrySet().iterator();
            while (iterable.hasNext()) {
                Map.Entry<String,Long> e = iterable.next();
                long time = e.getValue();
                if (baseLine > time) {
                    String topic = e.getKey();
                    mqttPahoMessageDrivenChannelAdapter.removeTopic(topic);
                    iterable.remove();
                    log.info("mqtt订阅的topic,过期时间5分钟,本次移除的topic="+topic);
                }
            }
        }
    }
}
  • 10
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值