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 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详细错误请查看日志文件。"; } }