springboot项目集成mqtt订阅信息websoket推送

pom.xml
<dependency>
            <groupId>org.eclipse.paho</groupId>
            <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
            <version>1.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

yml

server:
  port: 8810
spring:
  application:
    name: dp-alarm
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://ip:3306/database?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=true&zeroDateTimeBehavior=convertToNull&serverTimezone=UTC
    username: root
    password: password
    type: com.zaxxer.hikari.HikariDataSource

  mvc:
    static-path-pattern: /**

mqtt:
  url: tcp://ip:1883
  username: root
  password: root
  topic: lbmqtt
#  qos: 1                         # QoS 级别
#  keep-alive-interval: 60        # 心跳间隔(秒)
#  connection-timeout: 10

logging:
  level:
    org.springframework.jdbc.core.JdbcTemplate: DEBUG


data:
  type: MBTCP_D1
MosquittoMQTT
package com.dp.utils.mqtt;

import com.dp.service.UpService;
import com.dp.utils.io.ENS;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;

/**
 * Created by lenovo on 2022/11/9.
 */
@Component
@EnableAsync
public class MosquittoMQTT implements ApplicationRunner {
    @Autowired
    UpService upService;

    @Override
    public void run(ApplicationArguments applicationArguments) throws Exception {
        mqttClient();
    }

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

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

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

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

    @Value("${data.type}")
    private String type;

    @Async
    public void mqttClient(){
        String clientID = ENS.getUUID();;
        int qos = 1;
        System.out.println(url+username+password);
        MqttSubscriber mqttSubscriber = new MqttSubscriber(url,clientID,username,password,type);
        mqttSubscriber.subscribe(upService,topic,qos,username,password,type);
    }

}

  

MqttSubscriber
package com.dp.utils.mqtt;

import com.alibaba.fastjson.*;
import com.dp.service.UpService;
import com.dp.utils.enmu.CommonEnum;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;

/**
 * Created by lenovo on 2022/11/2.
 */

public class MqttSubscriber {

    private String type;
    private String username;
    private String password;


    private MqttClient mqttClient;

    public MqttSubscriber(String SERVER_URI, String CLIENT_ID, String username, String password,String type) {
        try {
            this.type = type;
            this.username = username;
            this.password = password;
            MemoryPersistence persistence = new MemoryPersistence();
            mqttClient = new MqttClient(SERVER_URI, CLIENT_ID, persistence);
            MqttConnectOptions connOpts = new MqttConnectOptions();
            connOpts.setCleanSession(false);//false
            connOpts.setUserName(username);
            connOpts.setPassword(password.toCharArray());
            connOpts.setConnectionTimeout(30);
            connOpts.setKeepAliveInterval(60);
            connOpts.setAutomaticReconnect(true);
            mqttClient.connect(connOpts);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public void subscribe(UpService upService, String topic, int qos,String username,String password,String type) {
        this.type = type;
        if (mqttClient == null) {
            return;
        }
        try {
            mqttClient.subscribe(topic, qos);
            mqttClient.setCallback(new MqttCallback() {
                @Override
                public void connectionLost(Throwable throwable) {
                    System.out.println("连接丢失,丢失原因为:"+throwable.getMessage());
                    CommonEnum.isconn = true;
                    // 使用循环重试,避免单次失败后停止
                    new Thread(() -> {
                        int retryCount = 0;
                        while (true) {
                            try {
                                // 每次重连前先断开旧连接(防止状态残留)
                                if (mqttClient != null && mqttClient.isConnected()) {
                                    try {
                                        mqttClient.disconnect();
                                    } catch (Exception e) {
                                        System.out.println("断开旧连接失败:" + e.getMessage());
                                    }
                                }

                                // 重新设置连接参数(复用原构造函数中的配置,避免默认参数问题)
                                if (mqttClient == null) {
                                    System.out.println("mqttClient 为空,无法重连");
                                    break;
                                }
                                // 重新连接(使用原连接选项,需在 MqttSubscriber 中保存 connOpts)
                                MqttConnectOptions connOpts = new MqttConnectOptions();
                                connOpts.setCleanSession(true);
                                connOpts.setUserName(username); // 需在 MqttSubscriber 中保存 username 字段
                                connOpts.setPassword(password.toCharArray()); // 保存 password 字段
                                connOpts.setConnectionTimeout(10);
                                connOpts.setKeepAliveInterval(20);
                                connOpts.setAutomaticReconnect(true);

                                mqttClient.connect(connOpts);
                                mqttClient.subscribe(topic, qos); // 重新订阅主题
                                System.out.println("MQTT 重连成功!");
                                retryCount = 0; // 重置重试计数
                                break; // 重连成功后退出循环

                            } catch (Exception e) {
                                retryCount++;
                                // 指数退避重试(避免频繁重试导致服务器压力)
                                long sleepTime = Math.min(1000 * (1 << retryCount), 30000); // 1s, 2s, 4s... 最大30s
                                System.out.println("第 " + retryCount + " 次重连失败," + sleepTime + "ms 后重试:" + e.getMessage());
                                e.printStackTrace();
                                try {
                                    Thread.sleep(sleepTime);
                                } catch (InterruptedException ie) {
                                    Thread.currentThread().interrupt();
                                    break;
                                }
                            }
                        }
                    }).start();
                }

                @Override
                public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
//                    String str = new String(mqttMessage.getPayload(),"GB2312").replaceAll("\\s", "");
                    String str = new String(mqttMessage.getPayload(),StandardCharsets.UTF_8).replaceAll("\\s", "");

//                    List<Map<String,Object>> list = new ArrayList<>();
                    try {
//                        List<Map<String,Object>> list1 = (List<Map<String, Object>>) JSON.parse(str);
                        Map<String,Object> map = (Map<String, Object>) JSON.parse(str);
                        Map<String,Object> map1 = (Map<String, Object>) map.get("data");
//                        禹王:ZDWXY_D1
//                        瑞赛科:MBTCP_D1
                        List<Map<String, Object>> list1 = (List<Map<String, Object>>)map1.get(type);
                        Data data = SpringContextUtil.getDataInstance();
                        data.setLs(list1);
                    } catch (Exception e) {
                        System.out.println("数据转换异常");
                        e.printStackTrace();
                    }
                }

                @Override
                public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
                    System.out.println("delivery isComplete:" + iMqttDeliveryToken.isComplete());
                }

            });
        } catch (MqttException e) {
            System.out.println(e.getMessage());
        }
    }

    public void disconnect() {
        if (mqttClient != null && mqttClient.isConnected()) {
            try {
                mqttClient.disconnect();
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }
    }



}
SpringContextUtil

  

package com.dp.utils.mqtt;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * @author LLF
 * @title SpringContextUtil
 * @date 2025/10/16 19:15
 * @description TODO
 */
@Component
public class SpringContextUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        applicationContext = context;
    }

    // 静态方法:获取 Data 实例
    public static Data getDataInstance() {
        return applicationContext.getBean(Data.class);
    }
}

  

Data
package com.dp.utils.mqtt;

import com.dp.service.UpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author LLF
 * @title Data
 * @date 2025/10/16 16:46
 * @description TODO
 */
@Component
@EnableAsync
public class Data {

    @Autowired
    private UpService upService;

    private List<Map<String, Object>> ls = new CopyOnWriteArrayList<>();

    public Data(){
        this.ls = new CopyOnWriteArrayList<>();
    }

    @Scheduled(cron = "0/10 * * * * ?")
    @Async
    public void insertData() {
        try {
            if (ls != null && !ls.isEmpty()) {
                upService.saveData(ls);
                ls.clear();
            }else{
                System.out.println("保存数据为空:"+ls);
            }
        } catch (Exception e) {
            System.out.println("保存数据失败,原因如下:");
            e.printStackTrace();
        }
    }

    public void setLs(List<Map<String, Object>> newLs) {
        if (newLs != null && !newLs.isEmpty()) {
            ls = newLs;
        }
    }

    public List<Map<String, Object>> getLs() {
        return ls;
    }
}

  

posted @ 2025-10-20 10:32  _Lawrence  阅读(5)  评论(0)    收藏  举报