diff --git a/src/main/java/com/example/demo/common/base/BaseStartupOutput.java b/src/main/java/com/example/demo/common/base/BaseStartupOutput.java new file mode 100644 index 0000000..c1bc761 --- /dev/null +++ b/src/main/java/com/example/demo/common/base/BaseStartupOutput.java @@ -0,0 +1,61 @@ +package com.example.demo.common.base; + +import org.springframework.boot.CommandLineRunner; +import org.springframework.core.env.Environment; +import org.springframework.context.ApplicationContext; + +/** + * 启动输出接口 + * 用于在SpringBoot启动后执行输出操作的Bean需要实现此接口 + * + * @author 岳佳君 (2025年09月29日 16:45:39) + * @version 1.0.0 + */ +public interface BaseStartupOutput extends CommandLineRunner { + + /** + * 获取执行优先级(数值越小优先级越高) + * + * @return 执行优先级 + */ + default int getOrder() { + return 0; + } + + /** + * 是否启用该输出 + * + * @return 是否启用 + */ + default boolean isEnabled() { + return true; + } + + /** + * 输出名称(用于日志标识) + * + * @return 输出名称 + */ + default String getOutputName() { + return this.getClass().getSimpleName(); + } + + /** + * 启动输出执行方法 + * + * @param environment 环境配置 + * @param context 应用上下文 + */ + void outputOnStartup(Environment environment, ApplicationContext context); + + /** + * CommandLineRunner接口的默认实现 + * + * @param args 命令行参数 + */ + @Override + default void run(String... args) { + // 由StartupOutputExecutor统一管理执行 + } + +} diff --git a/src/main/java/com/example/demo/common/base/defaults/StartupOutput.java b/src/main/java/com/example/demo/common/base/defaults/StartupOutput.java new file mode 100644 index 0000000..f9db7c0 --- /dev/null +++ b/src/main/java/com/example/demo/common/base/defaults/StartupOutput.java @@ -0,0 +1,26 @@ +package com.example.demo.common.base.defaults; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationContext; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +/** + * 启动默认输出 + * + * @author 岳佳君 (2025年9月29日 17:26:23) + * @version 1.0.0 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class StartupOutput implements com.example.demo.common.base.BaseStartupOutput { + @Override + public void outputOnStartup(Environment environment, ApplicationContext context) { + // 获取当前激活的环境(如dev、test、prod) + String[] activeProfiles = environment.getActiveProfiles(); + String activeProfile = activeProfiles.length > 0 ? activeProfiles[0] : "default"; + log.info("当前环境: {}", activeProfile); + } +} diff --git a/src/main/java/com/example/demo/common/config/springdoc/OpenApiStarterOutput.java b/src/main/java/com/example/demo/common/config/springdoc/OpenApiStarterOutput.java deleted file mode 100644 index 98e3c71..0000000 --- a/src/main/java/com/example/demo/common/config/springdoc/OpenApiStarterOutput.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.example.demo.common.config.springdoc; - -import lombok.RequiredArgsConstructor; -import org.springframework.boot.CommandLineRunner; -import org.springframework.boot.autoconfigure.web.ServerProperties; -import org.springframework.core.env.Environment; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -public class OpenApiStarterOutput implements CommandLineRunner { - - private final ServerProperties serverProperties; - private final Environment environment; - - @Override - public void run(String... args) throws Exception { - String pathInYaml = "server.servlet.context-path"; - String portInYaml = "server.port"; - - String port = environment.getProperty(portInYaml, "8080"); - String path = environment.getProperty(pathInYaml, ""); - - // 获取当前激活的环境(如dev、test、prod) - String[] activeProfiles = environment.getActiveProfiles(); - String activeProfile = activeProfiles.length > 0 ? activeProfiles[0] : "default"; - - // 输出包含环境信息和动态端口的API文档地址 - System.out.printf("当前环境: %s,API文档地址: http://localhost:%s%s/doc.html#/%n", - activeProfile, port, path); - } -} diff --git a/src/main/java/com/example/demo/common/executor/StartupOutputExecutor.java b/src/main/java/com/example/demo/common/executor/StartupOutputExecutor.java new file mode 100644 index 0000000..6df8732 --- /dev/null +++ b/src/main/java/com/example/demo/common/executor/StartupOutputExecutor.java @@ -0,0 +1,83 @@ +package com.example.demo.common.executor; + +import com.example.demo.common.base.BaseStartupOutput; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.context.ApplicationContext; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * 启动输出执行器 + * 统一管理所有BaseStartupOutput实现类的执行 + * + * @author 岳佳君 (2025年9月29日 17:18:32) + * @version 1.0.0 + */ +@Slf4j +@Component +public class StartupOutputExecutor implements ApplicationRunner { + + private final List outputs; + private final Environment environment; + private final ApplicationContext context; + + /** + * 构造函数 + * + * @param outputs 所有BaseStartupOutput实现类(可选依赖) + * @param environment 环境配置 + * @param context 应用上下文 + */ + public StartupOutputExecutor(List outputs, + Environment environment, + ApplicationContext context) { + this.outputs = outputs != null ? outputs : Collections.emptyList(); + this.environment = environment; + this.context = context; + } + + /** + * 执行所有启动输出 + * + * @param args 应用参数 + */ + @Override + public void run(ApplicationArguments args) { + if (outputs.isEmpty()) { + log.debug("未发现需要执行的启动输出"); + return; + } + + log.debug("开始执行启动输出,共发现 {} 个输出组件", outputs.size()); + + // 按优先级排序并执行 + outputs.stream() + .filter(BaseStartupOutput::isEnabled) + .sorted(Comparator.comparingInt(BaseStartupOutput::getOrder)) + .forEach(this::executeOutput); + + log.debug("启动输出执行完成"); + } + + /** + * 执行单个输出组件 + * + * @param output 输出组件 + */ + private void executeOutput(BaseStartupOutput output) { + String outputName = output.getOutputName(); + try { + log.trace("执行启动输出: {}", outputName); + output.outputOnStartup(environment, context); + log.trace("启动输出执行成功: {}", outputName); + } catch (Exception e) { + log.warn("启动输出执行失败: {}", outputName, e); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/common/output/ApiDocOutput.java b/src/main/java/com/example/demo/common/output/ApiDocOutput.java new file mode 100644 index 0000000..5ec0f5b --- /dev/null +++ b/src/main/java/com/example/demo/common/output/ApiDocOutput.java @@ -0,0 +1,51 @@ +package com.example.demo.common.output; + +import com.example.demo.common.base.BaseStartupOutput; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.env.Environment; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +/** + * API文档地址输出 + * 在启动后输出API文档访问地址 + * + * @author 岳佳君 (2025年09月29日 16:45:00) + * @version 1.0.0 + */ +@Slf4j +@Component +public class ApiDocOutput implements BaseStartupOutput { + + /** + * 获取执行优先级 + * + * @return 优先级(数值越小优先级越高) + */ + @Override + public int getOrder() { + return 10; + } + + /** + * 启动输出执行方法 + * + * @param environment 环境配置 + * @param context 应用上下文 + */ + @Override + public void outputOnStartup(Environment environment, ApplicationContext context) { + String port = environment.getProperty("server.port", "8080"); + String path = environment.getProperty("server.servlet.context-path", ""); + + String apiDocUrl = "http://localhost:" + port + path + "/doc.html"; + String swaggerUrl = "http://localhost:" + port + path + "/swagger-ui.html"; + + System.out.println("\n📚 API文档地址:"); + System.out.println(" • Knife4j文档: " + apiDocUrl); + log.trace("API文档地址输出完成 - Knife4j: {}", apiDocUrl); + + // System.out.println(" • Swagger文档: " + swaggerUrl); + // log.trace("API文档地址输出完成 - Knife4j: {}, Swagger: {}", apiDocUrl, swaggerUrl); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/common/output/AppConfigOutput.java b/src/main/java/com/example/demo/common/output/AppConfigOutput.java new file mode 100644 index 0000000..f12b0e8 --- /dev/null +++ b/src/main/java/com/example/demo/common/output/AppConfigOutput.java @@ -0,0 +1,67 @@ +package com.example.demo.common.output; + +import com.example.demo.common.base.BaseStartupOutput; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.env.Environment; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +/** + * 应用配置信息输出 + * 在启动后输出应用配置信息 + * + * @author 岳佳君 (2025年09月29日 16:45:00) + * @version 1.0.0 + */ +@Slf4j +@Component +public class AppConfigOutput implements BaseStartupOutput { + + /** + * 获取执行优先级 + * + * @return 优先级(数值越小优先级越高) + */ + @Override + public int getOrder() { + return 1; + } + + /** + * 启动输出执行方法 + * + * @param environment 环境配置 + * @param context 应用上下文 + */ + @Override + public void outputOnStartup(Environment environment, ApplicationContext context) { + System.out.println("\n🚀 XML解析器服务启动成功"); + System.out.println("📋 应用配置信息:"); + + // 服务器配置 + String port = environment.getProperty("server.port", "8080"); + String contextPath = environment.getProperty("server.servlet.context-path", ""); + String baseUrl = "http://localhost:" + port + contextPath; + + System.out.println(" • 服务端口: " + port); + System.out.println(" • 上下文路径: " + (contextPath.isEmpty() ? "/" : contextPath)); + System.out.println(" • 访问地址: " + baseUrl); + + // 激活的Profile + String[] activeProfiles = environment.getActiveProfiles(); + if (activeProfiles.length > 0) { + System.out.println(" • 激活配置: " + String.join(", ", activeProfiles)); + } else { + System.out.println(" • 激活配置: default"); + } + + // 应用信息 + String appName = environment.getProperty("spring.application.name", "xml-to-txt-service"); + String appVersion = environment.getProperty("app.version", "1.0.0"); + + System.out.println(" • 应用名称: " + appName); + System.out.println(" • 应用版本: " + appVersion); + + log.trace("应用配置信息输出完成 - 端口: {}, 上下文: {}", port, contextPath); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/common/output/DatabaseStatusOutput.java b/src/main/java/com/example/demo/common/output/DatabaseStatusOutput.java new file mode 100644 index 0000000..f0ab801 --- /dev/null +++ b/src/main/java/com/example/demo/common/output/DatabaseStatusOutput.java @@ -0,0 +1,80 @@ +package com.example.demo.common.output; + +import com.example.demo.common.base.BaseStartupOutput; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.env.Environment; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.SQLException; + +/** + * 数据库连接状态输出 + * 在启动后输出数据库连接状态 + * + * @author 岳佳君 (2025年09月29日 16:45:00) + * @version 1.0.0 + */ +@Slf4j +@Component +public class DatabaseStatusOutput implements BaseStartupOutput { + + /** + * 获取执行优先级 + * + * @return 优先级(数值越小优先级越高) + */ + @Override + public int getOrder() { + return 5; + } + + /** + * 启动输出执行方法 + * + * @param environment 环境配置 + * @param context 应用上下文 + */ + @Override + public void outputOnStartup(Environment environment, ApplicationContext context) { + System.out.println("\n🗄️ 数据库连接状态:"); + + // 检查SQLite数据库连接 + checkDataSource("SQLite", "sqlite", context); + + // 检查H2数据库连接 + checkDataSource("H2", "h2", context); + } + + /** + * 检查数据源连接状态 + * + * @param dbName 数据库名称 + * @param beanName Bean名称 + * @param context 应用上下文 + */ + private void checkDataSource(String dbName, String beanName, ApplicationContext context) { + try { + DataSource dataSource = context.getBean(beanName + "DataSource", DataSource.class); + if (dataSource != null) { + try (Connection connection = dataSource.getConnection()) { + if (connection.isValid(5)) { + System.out.println(" ✅ " + dbName + "数据库: 连接正常"); + log.trace("{}数据库连接正常", dbName); + } else { + System.out.println(" ❌ " + dbName + "数据库: 连接无效"); + log.trace("{}数据库连接无效", dbName); + } + } + } else { + System.out.println(" ⚠️ " + dbName + "数据库: 未配置"); + log.info("{}数据库未配置", dbName); + } + } catch (Exception e) { + System.out.println(" ❌ " + dbName + "数据库: 连接失败 - " + e.getMessage()); + log.warn("{}数据库连接失败: {}", dbName, e.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/main/resources/application-dm.yml b/src/main/resources/application-dm.yml new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/application-iotdb.yml b/src/main/resources/application-iotdb.yml new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/application-mysql.yml b/src/main/resources/application-mysql.yml new file mode 100644 index 0000000..e69de29