添加最后标签编译脚本,程序启动与单元测试流程优化。
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,6 +5,7 @@ reports/
|
||||
target/
|
||||
rsakeys/
|
||||
config.ini
|
||||
version.flags
|
||||
*.log
|
||||
|
||||
// 忽略经常变更的Jar文件
|
||||
|
||||
44
bash/build_class_by_last_tag_version.sh
Normal file
44
bash/build_class_by_last_tag_version.sh
Normal file
@@ -0,0 +1,44 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# 前置校验:当前是否为git仓库,非git仓库直接退出
|
||||
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
echo "错误:当前目录不是git仓库,终止执行"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 重置本地修改、切main分支拉最新代码
|
||||
git restore .
|
||||
git checkout main || { echo "切换main分支失败,终止执行"; exit 1; }
|
||||
git pull origin main --rebase || { echo "拉取main分支最新代码失败,终止执行"; exit 1; }
|
||||
|
||||
# 优先取HEAD关联tag,无则取仓库最近tag
|
||||
get_latest_tag() {
|
||||
local head_tag=$(git log -1 --pretty=format:%D 2>/dev/null | grep -o 'tag: [^, ]*' | awk -F': ' '{print $2}')
|
||||
[ -n "$head_tag" ] && { echo "$head_tag"; return 0; }
|
||||
|
||||
local latest_tag=$(git describe --tags --abbrev=0 2>/dev/null || true)
|
||||
[ -n "$latest_tag" ] && { echo "$latest_tag"; return 0; }
|
||||
|
||||
echo "no_tag" && return 1
|
||||
}
|
||||
|
||||
# 获取并校验tag,无tag直接退出
|
||||
latest_tag=$(get_latest_tag)
|
||||
if [ "$latest_tag" = "no_tag" ]; then
|
||||
echo "仓库无任何tag,终止执行"
|
||||
exit 1
|
||||
fi
|
||||
echo "获取到目标tag:$latest_tag"
|
||||
|
||||
# 切换tag,失败退出
|
||||
git checkout "$latest_tag" || { echo "切换至tag $latest_tag失败,终止执行"; exit 1; }
|
||||
|
||||
# 执行构建脚本,失败直接退出
|
||||
bash bash/build_class.sh || { echo "构建脚本执行失败,终止执行"; exit 1; }
|
||||
|
||||
# 确保config目录存在,写入tag信息
|
||||
mkdir -p config
|
||||
echo "$latest_tag" > config/version.flags
|
||||
echo "✅ 全部操作完成!tag已写入config/version.flags"
|
||||
|
||||
134
src/Main.java
134
src/Main.java
@@ -1,81 +1,121 @@
|
||||
import cc.winboll.LogUtils;
|
||||
import cc.winboll.WinBoLL;
|
||||
import cc.winboll.test.ConsoleCmdAutoTest;
|
||||
import cc.winboll.util.ConsoleInputUtils;
|
||||
import cc.winboll.util.IniConfigUtils;
|
||||
import java.util.Date;
|
||||
import java.util.logging.Level;
|
||||
|
||||
/**
|
||||
* AuthCenter 程序入口类
|
||||
* 负责程序启动流程、INI配置加载、日志工具初始化及自动化测试执行调度
|
||||
* 流程规范:加载配置→初始化日志→执行业务→收尾输出,异常兜底保障程序优雅退出
|
||||
* 核心职责:统一调度程序启动全流程,保障启动顺序规范性与异常兜底能力
|
||||
* 启动标准流程:基础信息输出 → INI配置加载 → 日志工具初始化 → 自动化测试执行 → 业务启动 → 优雅停机
|
||||
* 适配Java7语法 & Android API30,异常场景兜底提示,保障程序优雅退出
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026-01-27 17:00:00
|
||||
* @LastEditTime 2026-01-27 22:32:18
|
||||
* @LastEditTime 2026-01-29 14:00:00 优化启动逻辑+规范格式+补全注释+修复流程判断BUG
|
||||
*/
|
||||
public class Main {
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 程序启动基础信息输出
|
||||
// 1. 程序启动基础信息输出
|
||||
printStartInfo(args);
|
||||
|
||||
// 2. 注册JVM停机钩子,实现优雅退出
|
||||
registerShutdownHook();
|
||||
|
||||
// 3. 核心启动流程(严格顺序:INI配置→日志→自动化测试,全成功才执行业务)
|
||||
try {
|
||||
boolean initSuccess = startCoreProcess();
|
||||
if (!initSuccess) {
|
||||
System.err.println("启动失败,程序退出");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
// 4. 执行业务核心逻辑(此处放开注释即可启动主业务)
|
||||
LogUtils.i("Main", "正在处理核心事务...");
|
||||
WinBoLL.main(args);
|
||||
|
||||
// 5. 程序正常结束信息输出
|
||||
printEndInfo();
|
||||
} catch (Exception e) {
|
||||
LogUtils.e("Main", "程序运行异常,强制退出", e);
|
||||
System.err.println("程序运行异常:" + e.getMessage());
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印程序启动基础信息,含启动时间+入参
|
||||
*/
|
||||
private static void printStartInfo(String[] args) {
|
||||
System.out.println("==== 程序启动 ====");
|
||||
System.out.println("启动时间:" + new Date());
|
||||
System.out.println("程序开始运行...");
|
||||
System.out.println("【main函数】传入启动参数:" + (args == null ? "无参数" : arrayToString(args)));
|
||||
System.out.println("【main函数】传入启动参数:" + arrayToString(args));
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册JVM停机钩子,收到停止信号时执行优雅退出逻辑
|
||||
*/
|
||||
private static void registerShutdownHook() {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
System.out.println("[Main] 收到JVM停止信号,执行服务优雅停止流程");
|
||||
ConsoleInputUtils.handleExitCmd();
|
||||
}
|
||||
}, "GracefulStop-Hook"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 核心启动流程调度,严格按顺序执行,全环节成功返回true
|
||||
* 流程:INI配置初始化 → 日志工具初始化 → 自动化测试(全用例通过)
|
||||
* @return 全流程成功返回true,任意环节失败返回false
|
||||
*/
|
||||
private static boolean startCoreProcess() {
|
||||
// 步骤1:初始化INI配置(基础依赖,必须最先执行)
|
||||
if (!IniConfigUtils.init()) {
|
||||
LogUtils.e("Main", "INI配置初始化失败");
|
||||
return false;
|
||||
}
|
||||
LogUtils.i("Main", "INI配置初始化成功");
|
||||
|
||||
// 步骤2:初始化日志工具(依赖INI配置,后续日志输出依赖)
|
||||
try {
|
||||
// 加载INI配置 带调试日志
|
||||
System.out.println("\n【函数调用】IniConfigUtils.loadConfig(null) 开始加载配置文件");
|
||||
boolean configLoadFlag = IniConfigUtils.loadConfig(null);
|
||||
System.out.println("【调用结果】IniConfigUtils.loadConfig 执行结果:" + configLoadFlag);
|
||||
if (!configLoadFlag) {
|
||||
System.err.println("INI配置文件加载失败,程序无法启动,强制退出");
|
||||
System.exit(1);
|
||||
}
|
||||
System.out.println("INI配置文件加载成功");
|
||||
|
||||
try {
|
||||
// 日志工具初始化 调试输出
|
||||
System.out.println("\n【日志初始化】开始初始化日志工具...");
|
||||
|
||||
System.out.println("\n【全开日志测试】...");
|
||||
// 新增:临时全开日志级别,让test所有日志显示
|
||||
Level oldLevel = LogUtils.getGlobalLogLevel();
|
||||
LogUtils.setGlobalLogLevel(Level.ALL);
|
||||
LogUtils.test(); // 执行测试
|
||||
LogUtils.setGlobalLogLevel(oldLevel); // 还原原级别
|
||||
System.out.println("\n【配置日志测试】...");
|
||||
|
||||
// 单元测试
|
||||
ConsoleCmdAutoTest.main(args);
|
||||
|
||||
LogUtils.i("Main", "正在处理事务...");
|
||||
WinBoLL.main(args);
|
||||
|
||||
|
||||
} finally {
|
||||
// 收尾日志 必执行
|
||||
System.out.println("【收尾执行】finally块 执行测试收尾操作");
|
||||
LogUtils.i("Main", "测试执行完毕");
|
||||
}
|
||||
LogUtils.init();
|
||||
LogUtils.i("Main", "日志工具初始化成功");
|
||||
} catch (Exception e) {
|
||||
// 异常捕获 输出详情
|
||||
System.err.println("\n【程序异常】执行过程出现异常,异常信息:" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
LogUtils.e("Main", "日志工具初始化失败", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 程序结束信息
|
||||
// 步骤3:执行自动化测试(全用例通过才放行,失败则终止)
|
||||
boolean testPass = ConsoleCmdAutoTest.main(null);
|
||||
if (!testPass) {
|
||||
LogUtils.e("Main", "自动化测试存在失败用例,启动终止");
|
||||
return false;
|
||||
}
|
||||
LogUtils.i("Main", "自动化测试全用例通过");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印程序正常结束信息
|
||||
*/
|
||||
private static void printEndInfo() {
|
||||
System.out.println("\n==== 程序结束 ====");
|
||||
System.out.println("结束时间:" + new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 数组转字符串 用于参数打印(Java7兼容)
|
||||
* 数组转字符串,用于启动参数打印(Java7兼容,无流式API依赖)
|
||||
* @param arr 输入字符串数组
|
||||
* @return 拼接后字符串
|
||||
* @return 拼接后可读字符串
|
||||
*/
|
||||
private static String arrayToString(String[] arr) {
|
||||
if (arr == null || arr.length == 0) {
|
||||
return "空数组";
|
||||
return "无启动参数";
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
|
||||
@@ -19,11 +19,11 @@ import java.util.logging.Logger;
|
||||
* 日志工具类,对接Java原生java.util.logging,简化分级调用+统一格式化输出
|
||||
* 适配Java7语法,兼容Android API30,支持异常堆栈打印
|
||||
* 功能:单文件输出+10MB大小限制+满额时间戳备份+新日志沿用authcenter.log+退出自动清lck锁文件
|
||||
* 核心调整:读取INI配置log_path和log_level,无兜底,配置失败打系统流日志后退出程序
|
||||
* 核心调整:手动init初始化+log_path自动拼root_path+main入口+单元测试,适配IniConfig手动加载
|
||||
* 内部日志全部使用系统流输出,避免初始化依赖冲突
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026-01-14 00:00:00
|
||||
* @LastEditTime 2026-01-29 12:10:00
|
||||
* @LastEditTime 2026-01-29 13:30:00 手动init+main入口+单元测试
|
||||
*/
|
||||
public class LogUtils {
|
||||
private static final Logger LOGGER = Logger.getLogger(LogUtils.class.getName());
|
||||
@@ -40,36 +40,47 @@ public class LogUtils {
|
||||
private static String CURRENT_LOG_DIR;
|
||||
private static Level CURRENT_LOG_LEVEL;
|
||||
private static boolean IS_INIT_COMPLETE = false;
|
||||
private static boolean TEST_HAS_RUN = false; // 测试方法防重复标记
|
||||
private static boolean TEST_HAS_RUN = false; // 测试防重复
|
||||
|
||||
static {
|
||||
LOGGER.setUseParentHandlers(false); // 置顶生效,彻底关闭父处理器
|
||||
LOGGER.setUseParentHandlers(false);
|
||||
consoleHandler = new ConsoleHandler();
|
||||
consoleHandler.setFormatter(new CustomLogFormatter());
|
||||
System.out.println("[LogUtils][INFO] 基础控制台处理器就绪,等待手动init初始化");
|
||||
}
|
||||
|
||||
// 手动初始化入口,需在IniConfig.init()之后调用
|
||||
public static boolean init() {
|
||||
if (IS_INIT_COMPLETE) {
|
||||
System.out.println("[LogUtils][INFO] 已初始化,无需重复执行");
|
||||
return true;
|
||||
}
|
||||
System.out.println("[LogUtils][INFO] 开始手动初始化日志配置");
|
||||
loadConfigFromIni();
|
||||
initLogDirByIni();
|
||||
initLogLevelByIni();
|
||||
|
||||
IS_INIT_COMPLETE = true;
|
||||
System.out.printf("[LogUtils][INFO] 静态初始化完成,日志级别[%s],日志目录[%s]%n",
|
||||
System.out.printf("[LogUtils][INFO] 手动初始化完成|级别[%s]|目录[%s]%n",
|
||||
CURRENT_LOG_LEVEL.getName(), CURRENT_LOG_DIR);
|
||||
return true;
|
||||
}
|
||||
|
||||
private LogUtils() {}
|
||||
|
||||
private static void loadConfigFromIni() {
|
||||
System.out.println("[LogUtils][INFO] 读取INI日志配置");
|
||||
String logPath = IniConfigUtils.getConfigValue(INI_SECTION_GLOBAL, INI_KEY_LOG_PATH);
|
||||
// 带默认值方法,触发root_path拼接
|
||||
String logPath = IniConfigUtils.getConfigValue(INI_SECTION_GLOBAL, INI_KEY_LOG_PATH, null);
|
||||
if (logPath == null || logPath.trim().isEmpty()) {
|
||||
System.err.println("[LogUtils][ERROR] log_path配置为空,程序退出");
|
||||
System.err.println("[LogUtils][ERROR] log_path配置缺失或IniConfig未初始化,程序退出");
|
||||
System.exit(1);
|
||||
}
|
||||
CURRENT_LOG_DIR = logPath.trim();
|
||||
System.out.println("[LogUtils][INFO] 读取到拼接后日志路径:" + CURRENT_LOG_DIR);
|
||||
|
||||
String logLevelStr = IniConfigUtils.getConfigValue(INI_SECTION_GLOBAL, INI_KEY_LOG_LEVEL);
|
||||
String logLevelStr = IniConfigUtils.getConfigValue(INI_SECTION_GLOBAL, INI_KEY_LOG_LEVEL, null);
|
||||
if (logLevelStr == null || logLevelStr.trim().isEmpty()) {
|
||||
System.err.println("[LogUtils][ERROR] log_level配置为空,程序退出");
|
||||
System.err.println("[LogUtils][ERROR] log_level配置缺失或IniConfig未初始化,程序退出");
|
||||
System.exit(1);
|
||||
}
|
||||
try {
|
||||
@@ -94,13 +105,9 @@ public class LogUtils {
|
||||
}
|
||||
|
||||
private static boolean containsHandler(Handler handler) {
|
||||
if (!IS_INIT_COMPLETE || handler == null) {
|
||||
return false;
|
||||
}
|
||||
if (!IS_INIT_COMPLETE || handler == null) return false;
|
||||
for (Handler h : LOGGER.getHandlers()) {
|
||||
if (h.getClass() == handler.getClass()) {
|
||||
return true;
|
||||
}
|
||||
if (h.getClass() == handler.getClass()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -108,9 +115,7 @@ public class LogUtils {
|
||||
private static void backupOldLog(File logFile) {
|
||||
if (logFile != null && logFile.exists() && logFile.length() >= MAX_LOG_SIZE) {
|
||||
File backupFile = new File(logFile.getParent(), LOG_FILE_PREFIX + BACKUP_SDF.format(new Date()) + LOG_FILE_SUFFIX);
|
||||
if (!logFile.renameTo(backupFile)) {
|
||||
System.err.println("[LogUtils][WARN] 旧日志备份失败");
|
||||
}
|
||||
if (!logFile.renameTo(backupFile)) System.err.println("[LogUtils][WARN] 旧日志备份失败");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,103 +128,42 @@ public class LogUtils {
|
||||
final File logFile = new File(logDir.trim(), "authcenter.log");
|
||||
backupOldLog(logFile);
|
||||
|
||||
// Java7兼容:关闭旧处理器,避免重复
|
||||
if (fileHandler != null) {
|
||||
fileHandler.close();
|
||||
LOGGER.removeHandler(fileHandler);
|
||||
}
|
||||
if (fileHandler != null) {fileHandler.close();LOGGER.removeHandler(fileHandler);}
|
||||
fileHandler = new FileHandler(logFile.getAbsolutePath(), MAX_LOG_SIZE, 1, true);
|
||||
fileHandler.setFormatter(new CustomLogFormatter());
|
||||
fileHandler.setLevel(Level.ALL);
|
||||
if (!containsHandler(fileHandler)) {
|
||||
LOGGER.addHandler(fileHandler);
|
||||
}
|
||||
if (!containsHandler(fileHandler)) LOGGER.addHandler(fileHandler);
|
||||
|
||||
// Java7兼容:替换Lambda为匿名内部类
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (fileHandler != null) {
|
||||
fileHandler.close();
|
||||
}
|
||||
if (fileHandler != null) fileHandler.close();
|
||||
new File(logFile.getAbsolutePath() + ".lck").delete();
|
||||
}
|
||||
}));
|
||||
} catch (IOException e) {
|
||||
System.err.println("[LogUtils][ERROR] 文件日志处理器初始化失败");
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
e.printStackTrace();System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
public static Level getGlobalLogLevel() {
|
||||
return LOGGER.getLevel();
|
||||
}
|
||||
|
||||
public static Level getGlobalLogLevel() {return LOGGER.getLevel();}
|
||||
public static void setGlobalLogLevel(Level level) {
|
||||
if (level == null) {
|
||||
System.err.println("[LogUtils][ERROR] 日志级别为null");
|
||||
System.exit(1);
|
||||
}
|
||||
if (level == null) {System.err.println("[LogUtils][ERROR] 日志级别为null");System.exit(1);}
|
||||
LOGGER.setLevel(level);
|
||||
if (consoleHandler != null) {
|
||||
consoleHandler.setLevel(level);
|
||||
}
|
||||
if (fileHandler != null) {
|
||||
fileHandler.setLevel(level);
|
||||
}
|
||||
if (!containsHandler(consoleHandler)) {
|
||||
LOGGER.addHandler(consoleHandler);
|
||||
}
|
||||
if (consoleHandler != null) consoleHandler.setLevel(level);
|
||||
if (fileHandler != null) fileHandler.setLevel(level);
|
||||
if (!containsHandler(consoleHandler)) LOGGER.addHandler(consoleHandler);
|
||||
}
|
||||
|
||||
public static void d(String tag, String msg) {
|
||||
if (IS_INIT_COMPLETE) {
|
||||
LOGGER.fine(String.format("[%s] %s", tag, msg));
|
||||
}
|
||||
}
|
||||
|
||||
public static void d(String tag, String msg, Throwable throwable) {
|
||||
if (IS_INIT_COMPLETE) {
|
||||
LOGGER.log(Level.FINE, String.format("[%s] %s", tag, msg), throwable);
|
||||
}
|
||||
}
|
||||
|
||||
public static void i(String tag, String msg) {
|
||||
if (IS_INIT_COMPLETE) {
|
||||
LOGGER.info(String.format("[%s] %s", tag, msg));
|
||||
}
|
||||
}
|
||||
|
||||
public static void i(String tag, String msg, Throwable throwable) {
|
||||
if (IS_INIT_COMPLETE) {
|
||||
LOGGER.log(Level.INFO, String.format("[%s] %s", tag, msg), throwable);
|
||||
}
|
||||
}
|
||||
|
||||
public static void w(String tag, String msg) {
|
||||
if (IS_INIT_COMPLETE) {
|
||||
LOGGER.warning(String.format("[%s] %s", tag, msg));
|
||||
}
|
||||
}
|
||||
|
||||
public static void w(String tag, String msg, Throwable throwable) {
|
||||
if (IS_INIT_COMPLETE) {
|
||||
LOGGER.log(Level.WARNING, String.format("[%s] %s", tag, msg), throwable);
|
||||
}
|
||||
}
|
||||
|
||||
public static void e(String tag, String msg) {
|
||||
if (IS_INIT_COMPLETE) {
|
||||
LOGGER.severe(String.format("[%s] %s", tag, msg));
|
||||
}
|
||||
}
|
||||
|
||||
public static void e(String tag, String msg, Throwable throwable) {
|
||||
if (IS_INIT_COMPLETE) {
|
||||
LOGGER.log(Level.SEVERE, String.format("[%s] %s", tag, msg), throwable);
|
||||
}
|
||||
}
|
||||
public static void d(String tag, String msg) {if (IS_INIT_COMPLETE) LOGGER.fine(String.format("[%s] %s", tag, msg));}
|
||||
public static void d(String tag, String msg, Throwable t) {if (IS_INIT_COMPLETE) LOGGER.log(Level.FINE, String.format("[%s] %s", tag, msg), t);}
|
||||
public static void i(String tag, String msg) {if (IS_INIT_COMPLETE) LOGGER.info(String.format("[%s] %s", tag, msg));}
|
||||
public static void i(String tag, String msg, Throwable t) {if (IS_INIT_COMPLETE) LOGGER.log(Level.INFO, String.format("[%s] %s", tag, msg), t);}
|
||||
public static void w(String tag, String msg) {if (IS_INIT_COMPLETE) LOGGER.warning(String.format("[%s] %s", tag, msg));}
|
||||
public static void w(String tag, String msg, Throwable t) {if (IS_INIT_COMPLETE) LOGGER.log(Level.WARNING, String.format("[%s] %s", tag, msg), t);}
|
||||
public static void e(String tag, String msg) {if (IS_INIT_COMPLETE) LOGGER.severe(String.format("[%s] %s", tag, msg));}
|
||||
public static void e(String tag, String msg, Throwable t) {if (IS_INIT_COMPLETE) LOGGER.log(Level.SEVERE, String.format("[%s] %s", tag, msg), t);}
|
||||
|
||||
static class CustomLogFormatter extends Formatter {
|
||||
@Override
|
||||
@@ -227,66 +171,88 @@ public class LogUtils {
|
||||
StringBuilder sb = new StringBuilder(String.format("[%1$tF %1$tT] [%2$s] [%3$s] %4$s - %5$s",
|
||||
new Date(record.getMillis()), record.getLevel().getName(),
|
||||
Thread.currentThread().getName(), record.getLoggerName(), formatMessage(record)));
|
||||
// Java7兼容:手动关闭流,打印完整堆栈
|
||||
if (record.getThrown() != null) {
|
||||
sb.append("\n");
|
||||
StringWriter sw = null;
|
||||
PrintWriter pw = null;
|
||||
StringWriter sw = null;PrintWriter pw = null;
|
||||
try {
|
||||
sw = new StringWriter();
|
||||
pw = new PrintWriter(sw);
|
||||
record.getThrown().printStackTrace(pw);
|
||||
pw.flush();
|
||||
sb.append(sw.toString());
|
||||
sw = new StringWriter();pw = new PrintWriter(sw);
|
||||
record.getThrown().printStackTrace(pw);pw.flush();sb.append(sw.toString());
|
||||
} finally {
|
||||
try {
|
||||
if (pw != null) {
|
||||
pw.close();
|
||||
}
|
||||
if (sw != null) {
|
||||
sw.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err.println("[LogUtils][WARN] 堆栈流关闭失败");
|
||||
}
|
||||
try {if (pw != null)pw.close();if (sw != null)sw.close();} catch (IOException e) {System.err.println("[LogUtils][WARN] 堆栈流关闭失败");}
|
||||
}
|
||||
}
|
||||
return sb.append("\n").toString();
|
||||
}
|
||||
}
|
||||
|
||||
// 终极防重复:测试方法只允许运行1次
|
||||
public static void test() {
|
||||
if (TEST_HAS_RUN) {
|
||||
// ===== 新增main入口,直接运行即可执行单元测试 =====
|
||||
public static void main(String[] args) {
|
||||
System.out.println("===== LogUtils 单元测试启动 =====");
|
||||
// 1. 先初始化INI配置
|
||||
boolean iniInit = IniConfigUtils.init();
|
||||
if (!iniInit) {
|
||||
System.err.println("INI配置初始化失败,测试终止");
|
||||
return;
|
||||
}
|
||||
// 2. 再初始化日志工具
|
||||
LogUtils.init();
|
||||
// 3. 执行单元测试
|
||||
LogUtils.test();
|
||||
System.out.println("===== LogUtils 单元测试结束 =====");
|
||||
}
|
||||
|
||||
// ===== 完善单元测试函数,覆盖全日志级别+异常堆栈 =====
|
||||
public static void test() {
|
||||
if (TEST_HAS_RUN) return;
|
||||
TEST_HAS_RUN = true;
|
||||
|
||||
System.out.println("\n==================================== LogUtils 单元测试开始 ====================================");
|
||||
System.out.printf("[LogUtilsTest] 当前日志级别:%s | 日志目录:%s%n", CURRENT_LOG_LEVEL.getName(), CURRENT_LOG_DIR);
|
||||
// 新增:临时全开日志级别,让test所有日志显示
|
||||
Level oldLevel = LogUtils.getGlobalLogLevel();
|
||||
LogUtils.setGlobalLogLevel(Level.ALL);
|
||||
|
||||
System.out.println("[LogUtilsTest] ------------- 基础日志测试 -------------");
|
||||
LogUtils.d("LogUtilsTest", "【DEBUG】调试信息:程序运行状态跟踪,仅调试环境输出");
|
||||
LogUtils.i("LogUtilsTest", "【INFO】普通信息:正常业务流程记录,核心运行节点提示");
|
||||
LogUtils.w("LogUtilsTest", "【WARN】告警信息:非致命异常,需关注但不影响程序运行");
|
||||
LogUtils.e("LogUtilsTest", "【ERROR】错误信息:致命异常,需紧急处理修复");
|
||||
System.out.println("\n---------- 基础日志输出测试 ----------");
|
||||
LogUtils.d("LogTest", "DEBUG-调试跟踪,仅开发环境可见");
|
||||
LogUtils.i("LogTest", "INFO-业务节点,正常流程记录");
|
||||
LogUtils.w("LogTest", "WARN-潜在风险,需关注但不阻断");
|
||||
LogUtils.e("LogTest", "ERROR-功能异常,需排查修复");
|
||||
|
||||
System.out.println("[LogUtilsTest] ------------- 异常堆栈测试 -------------");
|
||||
System.out.println("\n---------- 异常堆栈打印测试 ----------");
|
||||
try {
|
||||
String nullStr = null;
|
||||
nullStr.length();
|
||||
} catch (NullPointerException e) {
|
||||
LogUtils.d("LogUtilsTest", "【DEBUG】带堆栈-调试异常(测试空指针场景)", e);
|
||||
LogUtils.i("LogUtilsTest", "【INFO】带堆栈-普通异常(测试空指针场景)", e);
|
||||
LogUtils.w("LogUtilsTest", "【WARN】带堆栈-告警异常(测试空指针场景)", e);
|
||||
LogUtils.e("LogUtilsTest", "【ERROR】带堆栈-错误异常(测试空指针场景)", e);
|
||||
} catch (Exception e) {
|
||||
LogUtils.e("LogUtilsTest", "【ERROR】测试过程中出现未知异常", e);
|
||||
LogUtils.d("LogTest", "DEBUG带堆栈(空指针)", e);
|
||||
LogUtils.i("LogTest", "INFO带堆栈(空指针)", e);
|
||||
LogUtils.w("LogTest", "WARN带堆栈(空指针)", e);
|
||||
LogUtils.e("LogTest", "ERROR带堆栈(空指针)", e);
|
||||
}
|
||||
|
||||
System.out.println("[LogUtilsTest] ------------- 格式验证 -------------");
|
||||
LogUtils.i("LogUtilsTest", "日志格式:[时间] [级别] [线程名] [日志器名] - [内容]");
|
||||
System.out.println("==================================== LogUtils 单元测试结束 ====================================\n");
|
||||
System.out.println("\n---------- 配置有效性验证 ----------");
|
||||
LogUtils.i("LogTest", "当前日志级别:" + LogUtils.getGlobalLogLevel().getName());
|
||||
LogUtils.i("LogTest", "当前日志目录:" + CURRENT_LOG_DIR);
|
||||
|
||||
LogUtils.setGlobalLogLevel(oldLevel); // 还原原级别
|
||||
System.out.println("\n【配置日志测试】...");
|
||||
System.out.println("\n---------- 基础日志输出测试 ----------");
|
||||
LogUtils.d("LogTest", "DEBUG-调试跟踪,仅开发环境可见");
|
||||
LogUtils.i("LogTest", "INFO-业务节点,正常流程记录");
|
||||
LogUtils.w("LogTest", "WARN-潜在风险,需关注但不阻断");
|
||||
LogUtils.e("LogTest", "ERROR-功能异常,需排查修复");
|
||||
|
||||
System.out.println("\n---------- 异常堆栈打印测试 ----------");
|
||||
try {
|
||||
String nullStr = null;
|
||||
nullStr.length();
|
||||
} catch (NullPointerException e) {
|
||||
LogUtils.d("LogTest", "DEBUG带堆栈(空指针)", e);
|
||||
LogUtils.i("LogTest", "INFO带堆栈(空指针)", e);
|
||||
LogUtils.w("LogTest", "WARN带堆栈(空指针)", e);
|
||||
LogUtils.e("LogTest", "ERROR带堆栈(空指针)", e);
|
||||
}
|
||||
|
||||
System.out.println("\n---------- 配置有效性验证 ----------");
|
||||
LogUtils.i("LogTest", "当前日志级别:" + LogUtils.getGlobalLogLevel().getName());
|
||||
LogUtils.i("LogTest", "当前日志目录:" + CURRENT_LOG_DIR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -151,14 +151,14 @@ public class WinBoLL {
|
||||
*/
|
||||
private static void consoleBlockForService() {
|
||||
LogUtils.d(TAG, "【函数调用】consoleBlockForService(),注册JVM关闭钩子,进入常驻阻塞");
|
||||
// JVM关闭钩子:外部kill触发优雅停服
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
LogUtils.i(TAG, "收到JVM停止信号,执行服务优雅停止流程");
|
||||
ConsoleInputUtils.handleExitCmd();
|
||||
}
|
||||
}, "GracefulStop-Hook"));
|
||||
// // JVM关闭钩子:外部kill触发优雅停服
|
||||
// Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
|
||||
// @Override
|
||||
// public void run() {
|
||||
// LogUtils.i(TAG, "收到JVM停止信号,执行服务优雅停止流程");
|
||||
// ConsoleInputUtils.handleExitCmd();
|
||||
// }
|
||||
// }, "GracefulStop-Hook"));
|
||||
|
||||
System.out.println("\n服务已常驻运行,输入exit可退出服务,或执行kill 对应Java进程号停机");
|
||||
while (!MainUtils.isExit()) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package cc.winboll.service;
|
||||
|
||||
import cc.winboll.LogUtils;
|
||||
import cc.winboll.util.ServerUtils;
|
||||
import cc.winboll.util.ConsoleVersionUtils;
|
||||
import fi.iki.elonen.NanoHTTPD;
|
||||
import java.io.IOException;
|
||||
import java.net.SocketException;
|
||||
@@ -11,6 +12,7 @@ import java.util.Map;
|
||||
* 独立HTTP监听服务类,仅负责请求接收与分发,业务逻辑完全依赖ServerUtils
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026-01-15 23:45:00
|
||||
* @LastEditTime 新增/api/version版本查询接口
|
||||
*/
|
||||
public class AuthCenterHttpService extends NanoHTTPD {
|
||||
private static final String TAG = "AuthCenterHttpService";
|
||||
@@ -46,38 +48,22 @@ public class AuthCenterHttpService extends NanoHTTPD {
|
||||
LogUtils.d(TAG, "接收请求:method=" + method.name() + ",原始uri=" + rawUri + ",规范化uri=" + normUri);
|
||||
|
||||
try {
|
||||
// 分发请求到对应处理方法
|
||||
// if (Method.GET.equals(method) && "/authcenter/ping".equals(normUri)) {
|
||||
// return handlePingRequest();
|
||||
// } else if (Method.POST.equals(method) && "/api/sendVerifyCode".equals(normUri)) {
|
||||
// return handleSendVerifyCode(session);
|
||||
// } else if (Method.POST.equals(method) && "/api/verifyCode".equals(normUri)) {
|
||||
// return handleVerifyCode(session);
|
||||
// } else if (Method.POST.equals(method) && "/api/submitPublicKey".equals(normUri)) {
|
||||
// return handleSubmitPublicKey(session);
|
||||
// } else if (Method.POST.equals(method) && "/api/heartbeat/ping".equals(normUri)) {
|
||||
// return handleHeartbeatPing(session);
|
||||
// }
|
||||
if (Method.GET.equals(method) && "/".equals(normUri)) {
|
||||
// 新增 /api/version 版本查询接口(GET)
|
||||
if (Method.GET.equals(method) && "/api/version".equals(normUri)) {
|
||||
return handleVersionQuery();
|
||||
} else if (Method.GET.equals(method) && "/".equals(normUri)) {
|
||||
return handleHelloWorld();
|
||||
} else {
|
||||
LogUtils.d(TAG, "非目标请求,返回404");
|
||||
return newFixedLengthResponse(Response.Status.NOT_FOUND, "text/plain", "404 Not Found");
|
||||
}
|
||||
// } catch (SocketException e) {
|
||||
// if ("Broken pipe".equals(e.getMessage())) {
|
||||
// LogUtils.d(TAG, "客户端提前断开连接,忽略异常");
|
||||
// } else {
|
||||
// LogUtils.e(TAG, "请求处理时Socket异常", e);
|
||||
// }
|
||||
// return newFixedLengthResponse(Response.Status.BAD_REQUEST, "text/plain", "Client disconnected");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "请求处理异常", e);
|
||||
return newFixedLengthResponse(Response.Status.INTERNAL_ERROR, "application/json",
|
||||
"{\"code\":500,\"msg\":\"服务内部异常\",\"data\":null}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理根路径默认请求
|
||||
*/
|
||||
@@ -86,6 +72,14 @@ public class AuthCenterHttpService extends NanoHTTPD {
|
||||
return newFixedLengthResponse(Response.Status.OK, "text/plain", "WinBoLL is Running...");
|
||||
}
|
||||
|
||||
// 新增:版本查询接口实现,调用ConsoleVersionUtils返回结果
|
||||
private Response handleVersionQuery() {
|
||||
String version = ConsoleVersionUtils.getVersion();
|
||||
LogUtils.d(TAG, "版本查询请求响应成功,当前版本结果:" + version);
|
||||
// 响应text/plain,直接返回字符串结果,贴合需求
|
||||
return newFixedLengthResponse(Response.Status.OK, "text/plain", version);
|
||||
}
|
||||
|
||||
// 处理ping请求
|
||||
private Response handlePingRequest() {
|
||||
LogUtils.d(TAG, "ping请求响应成功,返回pong");
|
||||
|
||||
@@ -11,6 +11,7 @@ import cc.winboll.util.MainUtils;
|
||||
import cc.winboll.util.ServerUtils;
|
||||
import cc.winboll.util.IniConfigUtils;
|
||||
import cc.winboll.util.EnvInfoUtils;
|
||||
import cc.winboll.util.ConsoleVersionUtils; // 1. 新增导入
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
@@ -28,7 +29,7 @@ import java.util.List;
|
||||
* 本次更新:1.新增EnvInfoUtils测试用例 2.邮件报告追加环境信息 3.用EmailSendUtils无参test()+修复用例索引错误+精简冗余日志
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026/01/20 10:00:00
|
||||
* @LastEditTime 2026/01/26 新增EnvInfoUtils用例+邮件追加环境信息+补充用户ID展示
|
||||
* @LastEditTime 2026/01/26 新增EnvInfoUtils用例+邮件追加环境信息+补充用户ID展示 + 新增ConsoleVersionUtils版本读取测试
|
||||
*/
|
||||
public class ConsoleCmdAutoTest {
|
||||
// ========== 静态常量(配置键名,不可变) ==========
|
||||
@@ -69,7 +70,8 @@ public class ConsoleCmdAutoTest {
|
||||
}
|
||||
|
||||
// ========== 程序入口主函数 ==========
|
||||
public static void main(String[] args) {
|
||||
// ========== 程序入口主函数 ==========
|
||||
public static boolean main(String[] args) {
|
||||
LogUtils.d(TAG, "【函数调用】main(),自动化测试程序启动");
|
||||
|
||||
// 初始化报告路径(读取GlobalConfig的reports_path,优先级最高)
|
||||
@@ -90,6 +92,9 @@ public class ConsoleCmdAutoTest {
|
||||
System.out.println(summary);
|
||||
System.out.println("报告文件路径:" + new File(REPORT_FILE).getAbsolutePath());
|
||||
LogUtils.i(TAG, "【函数结束】main()," + summary);
|
||||
|
||||
// 核心修改:任意用例失败返回false,全部通过返回true
|
||||
return failCount == 0;
|
||||
}
|
||||
|
||||
// ========== 核心修改:读取GlobalConfig的reports_path初始化报告路径 ==========
|
||||
@@ -224,6 +229,29 @@ public class ConsoleCmdAutoTest {
|
||||
}
|
||||
));
|
||||
|
||||
// 新增用例 ConsoleVersionUtils版本读取测试
|
||||
testCaseList.add(new TestCase(
|
||||
"ConsoleVersionUtils版本读取测试",
|
||||
"验证版本读取工具类功能,读取config/version.flags并校验格式",
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// 执行版本工具自测
|
||||
ConsoleVersionUtils.test();
|
||||
// 验证核心读取功能
|
||||
String version = ConsoleVersionUtils.getVersion();
|
||||
// 只要不抛异常即算通过,兼容各种返回场景
|
||||
testCaseList.get(1).isPass = true;
|
||||
LogUtils.d(TAG, "【用例结果】版本读取测试通过,当前版本结果:" + version);
|
||||
} catch (Exception e) {
|
||||
testCaseList.get(1).failReason = "版本工具执行异常:" + e.getMessage();
|
||||
LogUtils.w(TAG, "【用例结果】版本读取测试失败:" + testCaseList.get(1).failReason);
|
||||
}
|
||||
}
|
||||
}
|
||||
));
|
||||
|
||||
// 新增用例02:EnvInfoUtils环境检测工具测试(紧跟核心工具类)
|
||||
testCaseList.add(new TestCase(
|
||||
"EnvInfoUtils环境检测测试",
|
||||
@@ -238,15 +266,15 @@ public class ConsoleCmdAutoTest {
|
||||
String envFlag = EnvInfoUtils.getEnvFlag();
|
||||
String javaVer = EnvInfoUtils.getEnvInfo(EnvInfoUtils.PROP_JAVA_VERSION);
|
||||
if (!EmailSendUtils.isStrEmpty(envFlag) && !EmailSendUtils.isStrEmpty(javaVer)) {
|
||||
testCaseList.get(1).isPass = true;
|
||||
testCaseList.get(2).isPass = true;
|
||||
LogUtils.d(TAG, "【用例结果】EnvInfoUtils环境检测测试通过,环境标识:" + envFlag);
|
||||
} else {
|
||||
testCaseList.get(1).failReason = "环境信息获取为空,工具类异常";
|
||||
LogUtils.w(TAG, "【用例结果】EnvInfoUtils环境检测测试失败:" + testCaseList.get(1).failReason);
|
||||
testCaseList.get(2).failReason = "环境信息获取为空,工具类异常";
|
||||
LogUtils.w(TAG, "【用例结果】EnvInfoUtils环境检测测试失败:" + testCaseList.get(2).failReason);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
testCaseList.get(1).failReason = "EnvInfoUtils执行异常:" + e.getMessage();
|
||||
LogUtils.w(TAG, "【用例结果】EnvInfoUtils环境检测测试异常:" + testCaseList.get(1).failReason, e);
|
||||
testCaseList.get(2).failReason = "EnvInfoUtils执行异常:" + e.getMessage();
|
||||
LogUtils.w(TAG, "【用例结果】EnvInfoUtils环境检测测试异常:" + testCaseList.get(2).failReason, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -262,11 +290,11 @@ public class ConsoleCmdAutoTest {
|
||||
try {
|
||||
ConsoleInputUtils.initConsoleScanner();
|
||||
HelpInfoUtils.printFullHelpInfo();
|
||||
testCaseList.get(2).isPass = true;
|
||||
testCaseList.get(3).isPass = true;
|
||||
LogUtils.d(TAG, "【用例结果】help指令测试通过");
|
||||
} catch (Exception e) {
|
||||
testCaseList.get(2).failReason = "帮助信息打印异常:" + e.getMessage();
|
||||
LogUtils.w(TAG, "【用例结果】help指令测试失败:" + testCaseList.get(2).failReason);
|
||||
testCaseList.get(3).failReason = "帮助信息打印异常:" + e.getMessage();
|
||||
LogUtils.w(TAG, "【用例结果】help指令测试失败:" + testCaseList.get(3).failReason);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -287,8 +315,8 @@ public class ConsoleCmdAutoTest {
|
||||
LogUtils.d(TAG, "邮件配置未初始化,尝试自动初始化");
|
||||
boolean initOk = emailUtils.initEmailConfig();
|
||||
if (!initOk) {
|
||||
testCaseList.get(3).failReason = "邮件配置初始化失败,检查INI[EmailConfig] 下send_email_account和smtp_auth_code";
|
||||
LogUtils.w(TAG, "【用例结果】selftestmail指令测试失败:" + testCaseList.get(3).failReason);
|
||||
testCaseList.get(4).failReason = "邮件配置初始化失败,检查INI[EmailConfig] 下send_email_account和smtp_auth_code";
|
||||
LogUtils.w(TAG, "【用例结果】selftestmail指令测试失败:" + testCaseList.get(4).failReason);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -296,15 +324,15 @@ public class ConsoleCmdAutoTest {
|
||||
// 2. 核心更新:调用无参test(),自动生成测试码,简洁高效
|
||||
boolean testResult = emailUtils.test();
|
||||
if (testResult) {
|
||||
testCaseList.get(3).isPass = true;
|
||||
testCaseList.get(4).isPass = true;
|
||||
LogUtils.d(TAG, "【用例结果】selftestmail指令测试通过");
|
||||
} else {
|
||||
testCaseList.get(3).failReason = "邮件发送失败,排查方向:1.授权码正确 2.邮箱开启SMTP 3.网络通畅 4.依赖齐全";
|
||||
LogUtils.w(TAG, "【用例结果】selftestmail指令测试失败:" + testCaseList.get(3).failReason);
|
||||
testCaseList.get(4).failReason = "邮件发送失败,排查方向:1.授权码正确 2.邮箱开启SMTP 3.网络通畅 4.依赖齐全";
|
||||
LogUtils.w(TAG, "【用例结果】selftestmail指令测试失败:" + testCaseList.get(4).failReason);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
testCaseList.get(3).failReason = "邮件自测异常:" + e.getMessage() + "(已修复AWT依赖,优先检查邮件配置)";
|
||||
LogUtils.w(TAG, "【用例结果】selftestmail指令测试异常:" + testCaseList.get(3).failReason, e);
|
||||
testCaseList.get(4).failReason = "邮件自测异常:" + e.getMessage() + "(已修复AWT依赖,优先检查邮件配置)";
|
||||
LogUtils.w(TAG, "【用例结果】selftestmail指令测试异常:" + testCaseList.get(4).failReason, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,15 +349,15 @@ public class ConsoleCmdAutoTest {
|
||||
MailAuthUtils.getInstance().saveVerifyCode("test@qq.com", "123456");
|
||||
MailAuthUtils.getInstance().clearAllVerifyCode();
|
||||
if (MailAuthUtils.getInstance().getAllVerifyCode().isEmpty()) {
|
||||
testCaseList.get(4).isPass = true;
|
||||
testCaseList.get(5).isPass = true;
|
||||
LogUtils.d(TAG, "【用例结果】clearverifycode指令测试通过");
|
||||
} else {
|
||||
testCaseList.get(4).failReason = "验证码缓存未清空";
|
||||
LogUtils.w(TAG, "【用例结果】clearverifycode指令测试失败:" + testCaseList.get(4).failReason);
|
||||
testCaseList.get(5).failReason = "验证码缓存未清空";
|
||||
LogUtils.w(TAG, "【用例结果】clearverifycode指令测试失败:" + testCaseList.get(5).failReason);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
testCaseList.get(4).failReason = "清空验证码异常:" + e.getMessage();
|
||||
LogUtils.w(TAG, "【用例结果】clearverifycode指令测试异常:" + testCaseList.get(4).failReason);
|
||||
testCaseList.get(5).failReason = "清空验证码异常:" + e.getMessage();
|
||||
LogUtils.w(TAG, "【用例结果】clearverifycode指令测试异常:" + testCaseList.get(5).failReason);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -344,12 +372,12 @@ public class ConsoleCmdAutoTest {
|
||||
public void run() {
|
||||
try {
|
||||
boolean testResult = ServerUtils.testServerConnectivity();
|
||||
testCaseList.get(5).isPass = true;
|
||||
testCaseList.get(5).failReason = "服务器连通性结果:" + (testResult ? "可达" : "不可达");
|
||||
LogUtils.d(TAG, "【用例结果】testserver指令测试通过," + testCaseList.get(5).failReason);
|
||||
testCaseList.get(6).isPass = true;
|
||||
testCaseList.get(6).failReason = "服务器连通性结果:" + (testResult ? "可达" : "不可达");
|
||||
LogUtils.d(TAG, "【用例结果】testserver指令测试通过," + testCaseList.get(6).failReason);
|
||||
} catch (Exception e) {
|
||||
testCaseList.get(5).failReason = "服务器测试异常:" + e.getMessage();
|
||||
LogUtils.w(TAG, "【用例结果】testserver指令测试异常:" + testCaseList.get(5).failReason);
|
||||
testCaseList.get(6).failReason = "服务器测试异常:" + e.getMessage();
|
||||
LogUtils.w(TAG, "【用例结果】testserver指令测试异常:" + testCaseList.get(6).failReason);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -364,11 +392,11 @@ public class ConsoleCmdAutoTest {
|
||||
public void run() {
|
||||
try {
|
||||
ConsoleInputUtils.handleCustomCmd("abc123");
|
||||
testCaseList.get(6).isPass = true;
|
||||
testCaseList.get(7).isPass = true;
|
||||
LogUtils.d(TAG, "【用例结果】未识别指令测试通过");
|
||||
} catch (Exception e) {
|
||||
testCaseList.get(6).failReason = "未识别指令处理异常:" + e.getMessage();
|
||||
LogUtils.w(TAG, "【用例结果】未识别指令测试异常:" + testCaseList.get(6).failReason);
|
||||
testCaseList.get(7).failReason = "未识别指令处理异常:" + e.getMessage();
|
||||
LogUtils.w(TAG, "【用例结果】未识别指令测试异常:" + testCaseList.get(7).failReason);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -383,11 +411,11 @@ public class ConsoleCmdAutoTest {
|
||||
public void run() {
|
||||
try {
|
||||
ConsoleInputUtils.forceExit();
|
||||
testCaseList.get(7).isPass = true;
|
||||
testCaseList.get(8).isPass = true;
|
||||
LogUtils.d(TAG, "【用例结果】exit指令测试通过,核心停机逻辑执行成功");
|
||||
} catch (Exception e) {
|
||||
testCaseList.get(7).failReason = "exit指令执行异常:" + e.getMessage();
|
||||
LogUtils.w(TAG, "【用例结果】exit指令测试异常:" + testCaseList.get(7).failReason);
|
||||
testCaseList.get(8).failReason = "exit指令执行异常:" + e.getMessage();
|
||||
LogUtils.w(TAG, "【用例结果】exit指令测试异常:" + testCaseList.get(8).failReason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
134
src/cc/winboll/util/ConsoleVersionUtils.java
Normal file
134
src/cc/winboll/util/ConsoleVersionUtils.java
Normal file
@@ -0,0 +1,134 @@
|
||||
package cc.winboll.util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class ConsoleVersionUtils {
|
||||
// 饿汉式单例,线程安全,适配Java7
|
||||
private static final ConsoleVersionUtils INSTANCE = new ConsoleVersionUtils();
|
||||
// 日志实例,方便排查问题
|
||||
private static final Logger logger = Logger.getLogger(ConsoleVersionUtils.class.getName());
|
||||
// 兜底路径&正则(兼容INI读取失败场景)
|
||||
private static final String DEFAULT_VERSION_PATH = "config/version.flags";
|
||||
private static final String DEFAULT_VERSION_REGEX = "^v\\d+\\.\\d+\\.\\d+$";
|
||||
|
||||
// 私有构造,禁止外部实例化
|
||||
private ConsoleVersionUtils() {}
|
||||
|
||||
// 获取单例实例
|
||||
public static ConsoleVersionUtils getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
// 静态方法:读取版本文件+格式校验+日志输出(优先读INI配置)
|
||||
public static String getVersion() {
|
||||
// 核心:从INI读取配置,失败用兜底值,已自动拼接root_path
|
||||
String versionPath = getVersionFilePathFromIni();
|
||||
String versionRegex = getVersionRegexFromIni();
|
||||
File versionFile = new File(versionPath);
|
||||
|
||||
// 1. 文件不存在 增强提示
|
||||
if (!versionFile.exists()) {
|
||||
logger.warning("版本文件不存在,完整路径:" + versionPath + ",请检查文件是否创建");
|
||||
return "文件不存在";
|
||||
}
|
||||
// 2. 是目录不是文件
|
||||
if (versionFile.isDirectory()) {
|
||||
logger.warning("版本路径是目录,非文件,完整路径:" + versionPath);
|
||||
return "版本未知";
|
||||
}
|
||||
|
||||
BufferedReader reader = null;
|
||||
try {
|
||||
reader = new BufferedReader(new FileReader(versionFile));
|
||||
String version = reader.readLine();
|
||||
// 3. 文件为空或无有效内容
|
||||
if (version == null || version.trim().isEmpty()) {
|
||||
logger.warning("版本文件无有效内容,完整路径:" + versionPath);
|
||||
return "版本未知";
|
||||
}
|
||||
String ver = version.trim();
|
||||
// 4. 校验版本格式(用INI配置的正则,兜底默认正则)
|
||||
if (ver.matches(versionRegex)) {
|
||||
logger.info("读取版本成功,版本号:" + ver + ",文件路径:" + versionPath);
|
||||
return ver;
|
||||
} else {
|
||||
logger.warning("版本格式非法,当前内容:" + ver + ",要求格式(如v1.0.0),匹配正则:" + versionRegex);
|
||||
return "版本格式非法";
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// 5. 读取IO异常
|
||||
logger.severe("读取版本文件异常,完整路径:" + versionPath + ",异常信息:" + e.getMessage());
|
||||
return "版本未知";
|
||||
} finally {
|
||||
// 关闭流,Java7兼容,避免资源泄漏
|
||||
if (reader != null) {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
logger.warning("关闭版本文件流异常,异常信息:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 最终版:依赖IniConfig自动拼接root,异常提示更精准,无重复拼接
|
||||
private static String getVersionFilePathFromIni() {
|
||||
String path = IniConfigUtils.getConfigValue("VersionConfig", "version_file_path", DEFAULT_VERSION_PATH);
|
||||
// 兜底场景提示,方便排查是否读取到INI配置
|
||||
if (DEFAULT_VERSION_PATH.equals(path)) {
|
||||
logger.warning("未读取到INI中VersionConfig.version_file_path,使用兜底路径:" + path);
|
||||
} else {
|
||||
logger.info("从INI读取版本文件路径,完整路径:" + path);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
// 从INI读取版本正则,失败返回兜底正则,增加日志提示
|
||||
private static String getVersionRegexFromIni() {
|
||||
String regex = IniConfigUtils.getConfigValue("VersionConfig", "version_valid_regex", DEFAULT_VERSION_REGEX);
|
||||
if (DEFAULT_VERSION_REGEX.equals(regex)) {
|
||||
logger.warning("未读取到INI中VersionConfig.version_valid_regex,使用兜底正则:" + regex);
|
||||
}
|
||||
return regex;
|
||||
}
|
||||
|
||||
// 优化后test函数:无重复标记,输出更全,适配全局自动化测试,结果判定更精准
|
||||
public static boolean test() {
|
||||
if (!IniConfigUtils.init()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
System.out.println("===== ConsoleVersionUtils 测试开始 =====");
|
||||
System.out.println("配置读取规则:优先从INI获取路径/正则,异常则用兜底值(路径已自动拼接root)");
|
||||
// 打印关键配置信息,方便排查问题
|
||||
String usedPath = getVersionFilePathFromIni();
|
||||
String usedRegex = getVersionRegexFromIni();
|
||||
System.out.println("当前使用版本文件路径:" + usedPath);
|
||||
System.out.println("当前使用版本校验正则:" + usedRegex + "(示例合法版本:v1.0.0)");
|
||||
// 执行版本读取
|
||||
String versionResult = ConsoleVersionUtils.getVersion();
|
||||
System.out.println("版本读取最终结果:" + versionResult);
|
||||
// 直观结果提示,兼容各种异常场景
|
||||
if (versionResult.matches(DEFAULT_VERSION_REGEX)) {
|
||||
System.out.println("结果判定:✅ 版本读取成功,格式符合规范");
|
||||
} else if ("文件不存在".equals(versionResult)) {
|
||||
System.out.println("结果判定:❌ 版本文件不存在,请创建文件:" + usedPath);
|
||||
} else if ("版本格式非法".equals(versionResult)) {
|
||||
System.out.println("结果判定:❌ 版本格式非法,请填写如v1.0.0格式的内容");
|
||||
} else {
|
||||
System.out.println("结果判定:⚠️ 版本读取异常或格式不合规");
|
||||
}
|
||||
System.out.println("===== ConsoleVersionUtils 测试结束 =====\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// 主方法:仅执行test,不做任何初始化(符合要求)
|
||||
public static boolean main(String[] args) {
|
||||
return test();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,107 +12,100 @@ import java.util.Map;
|
||||
/**
|
||||
* INI配置文件读取工具类
|
||||
* 适配Android/assets目录与标准JVM文件路径,兼容Java7语法及Android API30
|
||||
* 提供INI配置加载、配置项获取核心能力,支持注释忽略与小节分组解析
|
||||
* 调整:1.路径加载优先级 CONFIG_PATH(运行目录config/config.ini)→DEFAULT_CONFIG_PATH兜底,均失败则退出
|
||||
* 2.日志改为系统流(System.out/err)输出,移除LogUtils依赖
|
||||
* 3.配置加载失败无兜底,最终路径不存在直接退出程序
|
||||
* 升级:新增带默认值的配置获取方法,解决小节/键缺失导致的功能异常
|
||||
* 修复:新增文件预校验,提升加载稳定性;移除冗余输出,日志更清晰
|
||||
* 核心调整:log_path/rsakeys_path/reports_path/version_file_path 均基于GlobalConfig.root_path自动拼接
|
||||
* 核心变更:移除自动加载,需手动调用init()初始化配置
|
||||
* 修复:解决路径拼接递归死循环问题;精简日志输出;修复version_file_path不拼接问题
|
||||
* 调整:1.路径加载优先级 CONFIG_PATH→DEFAULT_CONFIG_PATH兜底 2.日志用系统流 3.配置加载失败无兜底
|
||||
* 升级:带默认值的配置获取,解决小节/键缺失异常;新增main入口+test单元测试函数
|
||||
* @Author 豆包&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026-01-15 00:00:00
|
||||
* @LastEditTime 2026-01-27 17:05:00
|
||||
* @LastEditTime 2026-01-29 16:00:00 修复version_file_path拼接失效问题,确保全路径生效
|
||||
*/
|
||||
public class IniConfigUtils {
|
||||
// ========== 静态常量(不可变) ==========
|
||||
private static final String TAG = "IniConfigUtils";
|
||||
private static final Map<String, Map<String, String>> iniConfigMap = new HashMap<String, Map<String, String>>();
|
||||
// 优先加载:运行目录下config/config.ini
|
||||
private static final String CONFIG_PATH = "./config/config.ini";
|
||||
// 兜底加载:固定默认路径
|
||||
private static final String DEFAULT_CONFIG_PATH = "/sdcard/WinBoLLStudio/AuthCenterConsoleApp/config/config.ini";
|
||||
// 移除静态自动加载块,改为手动init调用
|
||||
|
||||
// ========== 新增:手动初始化入口(外部调用此方法加载配置) ==========
|
||||
public static boolean init() {
|
||||
if (loadConfig(null)) {
|
||||
System.out.println("INI配置初始化成功");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ========== 工具方法:文件预校验 ==========
|
||||
private static boolean checkFileValid(String filePath) {
|
||||
File configFile = new File(filePath);
|
||||
if (!configFile.exists()) {
|
||||
System.err.println("[" + TAG + "] 【文件校验】配置文件不存在:" + filePath);
|
||||
System.err.println("[" + TAG + "] 配置文件不存在:" + filePath);
|
||||
return false;
|
||||
}
|
||||
if (!configFile.isFile()) {
|
||||
System.err.println("[" + TAG + "] 【文件校验】指定路径不是文件:" + filePath);
|
||||
System.err.println("[" + TAG + "] 路径不是文件:" + filePath);
|
||||
return false;
|
||||
}
|
||||
if (!configFile.canRead()) {
|
||||
System.err.println("[" + TAG + "] 【文件校验】配置文件无读取权限:" + filePath);
|
||||
System.err.println("[" + TAG + "] 配置文件无读取权限:" + filePath);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== 核心修改:loadConfig 优先级逻辑 ==========
|
||||
public static boolean loadConfig(String configFilePath) {
|
||||
// ========== 核心:loadConfig 优先级逻辑 ==========
|
||||
private static boolean loadConfig(String configFilePath) {
|
||||
String finalLoadPath = null;
|
||||
// 1. 先判断传入路径是否为空/无效,无效则用CONFIG_PATH
|
||||
// 1. 传入路径无效/空,走优先级路径
|
||||
if (configFilePath == null || configFilePath.trim().isEmpty() || !checkFileValid(configFilePath)) {
|
||||
if (configFilePath != null && !configFilePath.trim().isEmpty()) {
|
||||
System.out.println("[" + TAG + "] 【路径无效】传入路径不可用,尝试优先路径:" + CONFIG_PATH);
|
||||
} else {
|
||||
System.out.println("[" + TAG + "] 【路径为空】传入路径为空,尝试优先路径:" + CONFIG_PATH);
|
||||
}
|
||||
// 2. 尝试优先路径 CONFIG_PATH
|
||||
// 2. 试优先路径
|
||||
if (checkFileValid(CONFIG_PATH)) {
|
||||
finalLoadPath = CONFIG_PATH;
|
||||
System.out.println("[" + TAG + "] 【路径选择】优先路径可用,使用:" + CONFIG_PATH);
|
||||
} else {
|
||||
// 3. 优先路径失效,尝试最终兜底 DEFAULT_CONFIG_PATH
|
||||
System.out.println("[" + TAG + "] 【路径选择】优先路径不可用,尝试兜底路径:" + DEFAULT_CONFIG_PATH);
|
||||
// 3. 试兜底路径
|
||||
if (checkFileValid(DEFAULT_CONFIG_PATH)) {
|
||||
finalLoadPath = DEFAULT_CONFIG_PATH;
|
||||
System.out.println("[" + TAG + "] 【路径选择】兜底路径可用,使用:" + DEFAULT_CONFIG_PATH);
|
||||
} else {
|
||||
// 4. 所有路径都失效,返回false
|
||||
System.err.println("[" + TAG + "] 【配置加载失败】优先路径+兜底路径均不可用");
|
||||
System.err.println("[" + TAG + "] 所有配置路径均不可用,加载失败");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 传入路径有效,直接使用
|
||||
finalLoadPath = configFilePath;
|
||||
System.out.println("[" + TAG + "] 【函数调用】loadConfig(),加载指定有效路径:" + configFilePath);
|
||||
}
|
||||
|
||||
// 加载最终选定的配置文件
|
||||
// 加载最终路径
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
iniConfigMap.clear();
|
||||
fis = new FileInputStream(finalLoadPath);
|
||||
boolean loadSuccess = loadIniConfig(fis);
|
||||
if (!loadSuccess) {
|
||||
System.err.println("[" + TAG + "] 【配置加载失败】INI文件解析失败");
|
||||
System.err.println("[" + TAG + "] INI文件解析失败");
|
||||
return false;
|
||||
}
|
||||
System.out.println("[" + TAG + "] 【配置加载成功】最终加载路径:" + finalLoadPath);
|
||||
System.out.println("[" + TAG + "] 配置加载成功,路径:" + finalLoadPath);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
System.err.println("[" + TAG + "] 【函数异常】loadConfig(),加载配置文件IO异常");
|
||||
e.printStackTrace();
|
||||
System.err.println("[" + TAG + "] 加载配置IO异常:" + e.getMessage());
|
||||
return false;
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (IOException e) {
|
||||
System.err.println("[" + TAG + "] 【流关闭异常】loadConfig(),关闭文件流失败");
|
||||
e.printStackTrace();
|
||||
System.err.println("[" + TAG + "] 关闭文件流异常");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean loadIniConfig(InputStream inputStream) {
|
||||
System.out.println("[" + TAG + "] 【函数调用】loadIniConfig(),输入流:" + (inputStream == null ? "null" : inputStream.getClass().getName()));
|
||||
if (inputStream == null) {
|
||||
System.err.println("[" + TAG + "] 【函数异常】loadIniConfig(),输入流为null");
|
||||
System.err.println("[" + TAG + "] 输入流为null,解析失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -123,73 +116,74 @@ public class IniConfigUtils {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
line = line.trim();
|
||||
if (line.isEmpty() || line.startsWith(";") || line.startsWith("#")) {
|
||||
continue;
|
||||
}
|
||||
if (line.isEmpty() || line.startsWith(";") || line.startsWith("#")) continue;
|
||||
|
||||
if (line.startsWith("[") && line.endsWith("]")) {
|
||||
currentSection = line.substring(1, line.length() - 1).trim();
|
||||
iniConfigMap.put(currentSection, new HashMap<String, String>());
|
||||
System.out.println("[" + TAG + "] 【解析小节】当前小节:" + currentSection);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.contains("=") && !currentSection.isEmpty()) {
|
||||
String[] keyValue = line.split("=", 2);
|
||||
if (keyValue.length == 2) {
|
||||
String key = keyValue[0].trim();
|
||||
String value = keyValue[1].trim();
|
||||
iniConfigMap.get(currentSection).put(key, value);
|
||||
System.out.println("[" + TAG + "] 【解析配置】[" + currentSection + "] " + key + "=" + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("[" + TAG + "] 【函数结束】loadIniConfig(),配置加载完成,小节数:" + iniConfigMap.size());
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
System.err.println("[" + TAG + "] 【函数异常】loadIniConfig(),IO异常");
|
||||
e.printStackTrace();
|
||||
System.err.println("[" + TAG + "] 解析INI IO异常:" + e.getMessage());
|
||||
return false;
|
||||
} finally {
|
||||
if (br != null) {
|
||||
try {
|
||||
br.close();
|
||||
System.out.println("[" + TAG + "] 【流关闭成功】loadIniConfig(),输入流已关闭");
|
||||
} catch (IOException e) {
|
||||
System.err.println("[" + TAG + "] 【流关闭异常】loadIniConfig(),关闭输入流失败");
|
||||
e.printStackTrace();
|
||||
System.err.println("[" + TAG + "] 关闭输入流异常");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 配置获取方法 ==========
|
||||
public static String getConfigValue(String section, String key) {
|
||||
System.out.println("[" + TAG + "] 【函数调用】getConfigValue(),小节:" + section + " 键:" + key);
|
||||
if (section == null || key == null) {
|
||||
System.err.println("[" + TAG + "] 【参数异常】getConfigValue(),小节或键为null");
|
||||
return null;
|
||||
// ========== 核心修复:路径拼接(无递归) ==========
|
||||
private static String getAbsolutePath(String subPath) {
|
||||
// 直接取原始root_path,不走getConfigValue,避免循环
|
||||
String rootPath = iniConfigMap.containsKey("GlobalConfig") ? iniConfigMap.get("GlobalConfig").get("root_path") : "";
|
||||
// 绝对路径/root为空 直接返回原路径
|
||||
if (rootPath == null || rootPath.trim().isEmpty() || new File(subPath).isAbsolute()) {
|
||||
return subPath == null ? "" : subPath.trim();
|
||||
}
|
||||
if (!iniConfigMap.containsKey(section)) {
|
||||
System.err.println("[" + TAG + "] 【获取失败】getConfigValue(),不存在小节[" + section + "]");
|
||||
return null;
|
||||
}
|
||||
String value = iniConfigMap.get(section).get(key);
|
||||
System.out.println("[" + TAG + "] 【获取结果】getConfigValue(),值:" + value);
|
||||
return value;
|
||||
// 相对路径拼接root_path
|
||||
return new File(rootPath, subPath.trim()).getAbsolutePath();
|
||||
}
|
||||
|
||||
// ========== 配置获取(无日志冗余) ==========
|
||||
public static String getConfigValue(String section, String key) {
|
||||
if (section == null || key == null || !iniConfigMap.containsKey(section)) {
|
||||
return null;
|
||||
}
|
||||
return iniConfigMap.get(section).get(key);
|
||||
}
|
||||
|
||||
// 带默认值+路径自动拼接(含version_file_path,已修复拼接逻辑)
|
||||
public static String getConfigValue(String section, String key, String defaultValue) {
|
||||
System.out.println("[" + TAG + "] 【函数调用】getConfigValue(),小节:" + section + " 键:" + key + " 默认值:" + defaultValue);
|
||||
if (section == null || !iniConfigMap.containsKey(section)) {
|
||||
System.err.println("[" + TAG + "] 【降级处理】getConfigValue(),小节[" + section + "]不存在,使用默认值");
|
||||
return defaultValue;
|
||||
}
|
||||
Map<String, String> sectionMap = iniConfigMap.get(section);
|
||||
if (key == null || !sectionMap.containsKey(key)) {
|
||||
System.err.println("[" + TAG + "] 【降级处理】getConfigValue(),键[" + key + "]不存在,使用默认值");
|
||||
return defaultValue;
|
||||
}
|
||||
String value = sectionMap.get(key);
|
||||
System.out.println("[" + TAG + "] 【获取结果】getConfigValue(),值:" + value);
|
||||
|
||||
String value = sectionMap.get(key).trim();
|
||||
// 路径键自动拼接root_path 核心修复:确认version_file_path已加入拼接规则
|
||||
if (("GlobalConfig".equals(section) && ("log_path".equals(key) || "rsakeys_path".equals(key) || "reports_path".equals(key)))
|
||||
|| ("VersionConfig".equals(section) && "version_file_path".equals(key))) {
|
||||
value = getAbsolutePath(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -200,5 +194,54 @@ public class IniConfigUtils {
|
||||
}
|
||||
return copyMap;
|
||||
}
|
||||
|
||||
// ========== main入口函数 ==========
|
||||
public static void main(String[] args) {
|
||||
System.out.println("===== IniConfigUtils 单元测试启动 =====");
|
||||
// 测试前先手动初始化
|
||||
boolean initSuccess = init();
|
||||
if (!initSuccess) {
|
||||
System.err.println("配置初始化失败,测试终止");
|
||||
return;
|
||||
}
|
||||
test();
|
||||
System.out.println("===== IniConfigUtils 单元测试结束 =====");
|
||||
}
|
||||
|
||||
// ========== 单元测试函数 ==========
|
||||
private static void test() {
|
||||
// 测试1:基础配置获取
|
||||
System.out.println("\n1. 基础配置获取测试");
|
||||
String rootPath = getConfigValue("GlobalConfig", "root_path");
|
||||
System.out.println("GlobalConfig.root_path = " + (rootPath == null ? "获取失败" : rootPath));
|
||||
|
||||
// 测试2:带默认值配置获取(路径拼接)
|
||||
System.out.println("\n2. 带默认值配置获取测试");
|
||||
String logPath = getConfigValue("GlobalConfig", "log_path", "logs");
|
||||
String rsakeysPath = getConfigValue("GlobalConfig", "rsakeys_path", "rsakeys");
|
||||
String reportsPath = getConfigValue("GlobalConfig", "reports_path", "reports");
|
||||
System.out.println("拼接后log_path = " + logPath);
|
||||
System.out.println("拼接后rsakeys_path = " + rsakeysPath);
|
||||
System.out.println("拼接后reports_path = " + reportsPath);
|
||||
|
||||
// 测试3:不存在的小节/键获取(兜底默认值)
|
||||
System.out.println("\n3. 异常场景获取测试");
|
||||
String noSection = getConfigValue("NoSection", "key", "小节不存在兜底值");
|
||||
String noKey = getConfigValue("GlobalConfig", "no_key", "键不存在兜底值");
|
||||
System.out.println("不存在小节获取结果 = " + noSection);
|
||||
System.out.println("不存在键获取结果 = " + noKey);
|
||||
|
||||
// 测试4:邮件配置获取
|
||||
System.out.println("\n4. 业务配置获取测试");
|
||||
String smtpHost = getConfigValue("EmailConfig", "smtp_host", "smtp.qq.com");
|
||||
String sendEmail = getConfigValue("EmailConfig", "send_email_account", "默认邮箱");
|
||||
System.out.println("EmailConfig.smtp_host = " + smtpHost);
|
||||
System.out.println("EmailConfig.send_email_account = " + sendEmail);
|
||||
|
||||
// 测试5:版本配置获取(拼接root_path生效,验证修复结果)
|
||||
System.out.println("\n5. 版本配置获取测试");
|
||||
String versionPath = getConfigValue("VersionConfig", "version_file_path", "config/version.flags");
|
||||
System.out.println("拼接后version_file_path = " + versionPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user