src/main/java/com/hwtd/mes/collect/DataAcquisitionApplication.java
@@ -1,13 +1,66 @@
package com.hwtd.mes.collect;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import javax.swing.JOptionPane;
import java.net.BindException;
@Slf4j
@SpringBootApplication
public class DataAcquisitionApplication {
    public static void main(String[] args) {
        SpringApplication.run(DataAcquisitionApplication.class, args);
        SpringApplication application = new SpringApplication(DataAcquisitionApplication.class);
        // 系统托盘图标依赖 AWT:Spring Boot 默认 java.awt.headless=true,这里必须关掉,否则托盘不会显示
        application.setHeadless(false);
        try {
            application.run(args);
        } catch (Throwable e) {
            // 双击 jar 启动用的是 javaw,没有控制台,启动失败时必须弹窗,否则用户什么都看不到
            showStartupError(e);
            System.exit(1);
        }
    }
    /**
     * 启动失败提示:写日志 + 弹窗
     */
    private static void showStartupError(Throwable error) {
        String message = buildStartupErrorMessage(error);
        try {
            log.error("数据采集器启动失败:{}", message, error);
        } catch (Throwable ignored) {
            // 日志系统还没初始化好时忽略
        }
        try {
            JOptionPane.showMessageDialog(null, message, "数据采集器启动失败", JOptionPane.ERROR_MESSAGE);
        } catch (Throwable t) {
            // 没有桌面会话时弹不了窗,只能靠日志
            System.err.println(message);
        }
    }
    /**
     * 组装启动失败提示:端口被占用时给出更明确的处理办法
     *
     * @param error 启动异常
     * @return 提示内容
     */
    public static String buildStartupErrorMessage(Throwable error) {
        Throwable root = error;
        while (root.getCause() != null && root.getCause() != root) {
            root = root.getCause();
        }
        String detail = root.getMessage() == null ? root.getClass().getName() : root.getMessage();
        if (root instanceof BindException
                || detail.contains("already in use")
                || detail.contains("Address already in use")) {
            return "服务端口已被占用,程序可能已经在运行。\n"
                    + "请先看任务栏右下角有没有采集器图标(右键 → 退出),"
                    + "或在任务管理器里结束对应的 java 进程后再启动。";
        }
        return "启动失败:" + detail + "\n详细错误请查看日志文件。";
    }
}