springBoot集成mqtt

springBoot集成mqtt

简介

EMQX是一款大规模可弹性伸缩的云原生分布式物联网 MQTT消息服务器。
作为全球最具扩展性的 MQTT 消息服务器,EMQX 提供了高效可靠海量物联网设备连接,能够高性能实时移动与处理消息和事件流数据,帮助您快速构建关键业务的物联网平台与应用。

下载

https://www.emqx.io/downloads

注意:下载安装后可能会有打不开的情况,此时需要安装Erlang环境。

这里下载安装以windows操作系统为例。

启动

  1. 进入解压后的bin目录

    启动路径
  2. 输入cmd进入dos命令窗口,输入 emqx start 命令启动,出现如下说明启动成功

    启动命令
  3. 访问控制台浏览器输入 http://localhost:18083 即可访问,默认账号密码 admin/public

    在控制台可以看到连接的设备相关信息

    控制台
  4. 关闭mqtt服务, 在bin目录下 输入 emqx stop 命令。

    关闭命令

springBoot集成mqtt

  1. 导入依赖
        <!--mqtt中间件-->
        <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>

  1. 编写配置
mqtt:
  hostUrl: tcp://127.0.0.1:1883
  username: guest
  password: 123456
  keepAliveInterval: 60
  connectionTimeout: 10
  client-id: mqttClient01
  server-id: mqttServer01
  data-topic: /wvp_ptz
  will-topic: /will
  will-content: mqttServer Unexpected disconnection
  completion-timeout: 10000
  1. 编写配置类
@Configuration
@IntegrationComponentScan
@Data
public class MqttConfig {

    /**
     * mqtt地址
     */
    @Value("${mqtt.hostUrl}")
    private String hostUrl;

    /**
     * 用户名
     */
    @Value("${mqtt.username}")
    private String username;

    /**
     * 密码
     */
    @Value("${mqtt.password}")
    private String password;

    /**
     * 心跳间隔
     */
    @Value("${mqtt.keepAliveInterval}")
    private int keepAliveInterval;

    /**
     *连接超时
     */
    @Value("${mqtt.connectionTimeout}")
    private int connectionTimeout;

    /**
     *客户端id
     */
    @Value("${mqtt.client-id}")
    private String clientId;

    /**
     *服务端id
     */
    @Value("${mqtt.server-id}")
    private String serverId;

    /**
     *消息主题
     */
    @Value("${mqtt.data-topic}")
    private String dataTopic;

    /**
     *遗愿主题
     */
    @Value("${mqtt.will-topic}")
    private String willTopic;

    /**
     *遗愿消息内容
     */
    @Value("${mqtt.will-content}")
    private String willContent;

    /**
     *断开连接超时时间
     */
    @Value("${mqtt.completion-timeout}")
    private long completionTimeout;


    @Bean
    public MqttConnectOptions getMqttConnectOptions(){
        MqttConnectOptions options = new MqttConnectOptions();
        // 设置发布端地址,多个用逗号分隔, 如:tcp://111:1883,tcp://222:1883
        // 当第一个111连接上后,222不会在连,如果111挂掉后,重试连111几次失败后,会自动去连接222
        options.setServerURIs(hostUrl.split(","));
        options.setKeepAliveInterval(keepAliveInterval);
        options.setUserName(username);
        options.setPassword(password.toCharArray());
        options.setConnectionTimeout(connectionTimeout);
        // 设置“遗嘱”消息的话题,若客户端与服务器之间的连接意外中断,服务器将发布客户端的“遗嘱”消息。
        options.setWill(willTopic,(clientId + willContent).getBytes(),1,true);
        // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,
        // 把配置里的 cleanSession 设为false,客户端掉线后 服务器端不会清除session,
        // 当重连后可以接收之前订阅主题的消息。当客户端上线后会接受到它离线的这段时间的消息
        options.setCleanSession(true);
        options.setMaxInflight(1000);

        //设置断开重新连接
        options.setAutomaticReconnect(true);
        return options;
    }

    @Bean
    public MqttPahoClientFactory mqttPahoClientFactory(){
        DefaultMqttPahoClientFactory clientFactory = new DefaultMqttPahoClientFactory();
        clientFactory.setConnectionOptions(getMqttConnectOptions());
        return clientFactory;
    }


    /**
     * 发送通道
     */
    @Bean
    public MessageChannel mqttOutBoundChannel(){
        return new DirectChannel();
    }

    /**
     * 发送消息配置
     * @return
     */
    @Bean
    @ServiceActivator(inputChannel = "mqttOutBoundChannel")
    public MessageHandler messageHandler(){
        //clientId每个连接必须唯一,否则,两个相同的clientId相互挤掉线
        //String clientIdStr = clientId + new SecureRandom().nextInt(10);
        MqttPahoMessageHandler mqttPahoMessageHandler = new MqttPahoMessageHandler(clientId,mqttPahoClientFactory());
        //async如果为true,则调用方不会阻塞。而是在发送消息时等待传递确认。默认值为false(发送将阻塞,直到确认发送)
        mqttPahoMessageHandler.setAsync(true);
        mqttPahoMessageHandler.setDefaultTopic(dataTopic);
        mqttPahoMessageHandler.setDefaultQos(1);
        mqttPahoMessageHandler.setAsyncEvents(true);
        return mqttPahoMessageHandler;
    }

    /**
     * 接收通道
     */
    @Bean
    public MessageChannel mqttInboundChannel(){
        return new DirectChannel();
    }

    /**
     * 配置监听的 topic 支持通配符
     * @return
     */
    @Bean
    public MessageProducer inBound(){
        String[] topics = new String[]{
                "$SYS/brokers/+/clients/+/disconnected", //客户端下线主题
                "$SYS/brokers/+/clients/+/connected",    //客户端上线主题
               // "$exclusive/",                           //排它策略前缀
                dataTopic,
                willTopic
        };
        //serverId每个连接必须唯一,否则,两个相同的serverId相互挤掉线
        //String serverIdStr = serverId + new SecureRandom().nextInt(10);
        MqttPahoMessageDrivenChannelAdapter adapter =
                new MqttPahoMessageDrivenChannelAdapter(serverId,mqttPahoClientFactory(),topics);
        adapter.setOutputChannel(mqttInboundChannel());
        adapter.setDisconnectCompletionTimeout(completionTimeout);
        adapter.setConverter(new DefaultPahoMessageConverter());
        adapter.setQos(1);
        return adapter;
    }

    /**
     * 通过通道获取数据
     * @return
     */
    @Bean
    @ServiceActivator(inputChannel = "mqttInboundChannel")
    public MessageHandler getInbound(){
        MessageHandler messageHandler = new MessageHandler() {
            @Override
            public void handleMessage(Message<?> message) throws MessagingException {
                String topic = message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC).toString();
                String payload = message.getPayload().toString();
                //消息处理
                //MyMessageHandler.msgHandler(topic,payload);
                System.out.println("消息主题:"+topic+",消息内容:"+payload);
                //处理订阅topic:(data/#)到的所有的数据
            }
        };
        return messageHandler;
    }


    /**
     * 连接失败会触发
     * @param event
     */
    @EventListener(classes = MqttConnectionFailedEvent.class)
    public void mqttConnectFailedEvent(MqttConnectionFailedEvent event){

        System.out.println("mqttConnectionFailedEvent连接mqtt失败: "+event.toString());
    }

    /**
     * @desc 当async和async事件(async-events)都为true时,将发出MqttMessageSentEvent
     * 它包含消息、主题、客户端库生成的消息id、clientId和clientInstance(每次连接客户端时递增)
     * @date 2021/7/22
     *@param event
     * @return void
     */
    @EventListener(classes = MqttMessageSentEvent.class)
    public void mqttMessageSentEvent(MqttMessageSentEvent event){
        System.out.println("发送消息"+event.toString());
    }

    /**
     * @desc 当async和async事件(async-events)都为true时,将发出MqttMessageDeliveredEvent
     * 当客户端库确认传递时,将发出MqttMessageDeliveredEvent。它包含messageId、clientId和clientInstance,使传递与发送相关。
     * @date 2021/7/22
     *@param event
     * @return void
     */
    @EventListener(classes = MqttMessageDeliveredEvent.class)
    public void mqttMessageDeliveredEvent(MqttMessageDeliveredEvent event){
        System.out.println("消息发送成功:"+event.toString());
    }

    /**
     * @desc 成功订阅到主题,MqttSubscribedEvent事件就会被触发(多个主题,多次触发)
     * @date 2021/7/22
     *@param event
     * @return void
     */
    @EventListener(classes = MqttSubscribedEvent.class)
    public void mqttSubscribedEvent(MqttSubscribedEvent event){
        System.out.println("消息订阅成功:"+event.toString());
    }
}
  1. 编写发送消息接口
@MessagingGateway(defaultRequestChannel = "mqttOutBoundChannel")
public interface MqttGateway {
    /**
     * 
     * @param data 消息
     */
    void send(String data);

    /**
     * 
     * @param data  消息
     * @param topic 主题
     */
    void send(String data, @Header(MqttHeaders.TOPIC) String topic);

    /**
     * 
     * @param data  消息
     * @param topic 主题
     * @param qos   消息质量
     */
    void send(String data, @Header(MqttHeaders.TOPIC) String topic,@Header(MqttHeaders.QOS) int qos);

}
  1. 编写 TestController
@RestController
public class TestController {

    @Autowired
    private MqttGateway mqttGateway;

    @RequestMapping("/test")
    public String testMqtt(@RequestParam(value = "msg") String msg){
        mqttGateway.send(msg,"/wvp_ptz",1);
        return "ok";
    }
    
}
  1. postman测试

    postman
    idea控制台
    ideaConsole
    mqtt面板
    ideaConsole

结束

到此springBoot已经集成mqtt了

posted @ 2023-03-08 13:39  cxf0616  阅读(968)  评论(0编辑  收藏  举报