From 1111991a9c3675f53b64d16379727b2aa6149997 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期一, 28 九月 2026 15:48:08 +0800
Subject: [PATCH] 厂商库口令改为优先读本地凭据文件,并在启动时自检
---
battery-device-neware/src/main/java/com/battery/device/neware/NewareMysqlAdapterFactory.java | 60 +++++++++++++++++++++++++++++++++++++++++++++++-------------
1 files changed, 47 insertions(+), 13 deletions(-)
diff --git a/battery-device-neware/src/main/java/com/battery/device/neware/NewareMysqlAdapterFactory.java b/battery-device-neware/src/main/java/com/battery/device/neware/NewareMysqlAdapterFactory.java
index 8e074a2..e83b882 100644
--- a/battery-device-neware/src/main/java/com/battery/device/neware/NewareMysqlAdapterFactory.java
+++ b/battery-device-neware/src/main/java/com/battery/device/neware/NewareMysqlAdapterFactory.java
@@ -1,8 +1,14 @@
package com.battery.device.neware;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Properties;
+import java.util.function.Function;
import com.battery.device.api.DeviceAdapter;
import com.battery.device.api.DeviceAdapterException;
import com.battery.device.api.model.AdapterCapabilities;
@@ -12,8 +18,9 @@
/**
* 按存储形态 {@code NEWARE_MYSQL} 构造直连厂商库的只读适配器实例。
*
- * <p>连接口令只从环境变量或启动参数读取(变量名由实例配置的 {@code passwordEnv} 指定,
- * 缺省为 {@link NewareMysqlAdapter#DEFAULT_PASSWORD_ENV}),不进数据库也不进仓库。
+ * <p>连接口令不进数据库、不进仓库,也不打包进 jar,取值顺序见 {@link #credential}:
+ * 本地凭据文件 → 同名环境变量 → 同名 JVM 启动参数。三者都没有时装配失败,
+ * 错误信息同时点名文件路径与变量名,使"忘了放口令"是可见的失败而不是沉默的缺失。
* 账号固定为现场取得的服务端只读账号,全权限账号不进入配置。
*/
public final class NewareMysqlAdapterFactory implements DeviceAdapterFactory
@@ -25,6 +32,8 @@
private static final String READ_ONLY_USER = "visitor";
/** 现场已知的全权限账号;写进交付配置就等于把误写风险带进现场。 */
private static final List<String> FULL_PRIVILEGE_USERS = List.of("btsserver", "root");
+ /** 凭据文件相对进程工作目录定位,使开发(仓库根)与交付(应用目录)用同一个位置。 */
+ static final Path CREDENTIALS_FILE = Path.of("config", "vendor-credentials.properties");
@Override
public String adapterType()
@@ -37,8 +46,10 @@
{
String database = option(config.sourceConfig(), DATABASE_OPTION, DEFAULT_DATABASE);
String user = readOnlyUser(config.sourceConfig());
- String password = credential(option(config.sourceConfig(), PASSWORD_ENV_OPTION,
- NewareMysqlAdapter.DEFAULT_PASSWORD_ENV));
+ String key = option(config.sourceConfig(), PASSWORD_ENV_OPTION,
+ NewareMysqlAdapter.DEFAULT_PASSWORD_ENV);
+ String password = credential(key, CREDENTIALS_FILE.toAbsolutePath(), System.getenv(),
+ System::getProperty);
SingleConnectionVendorDataSource source = new SingleConnectionVendorDataSource(
jdbcUrl(config.host(), config.port(), database), user, password);
return NewareMysqlAdapter.create(config, source);
@@ -58,16 +69,39 @@
return user;
}
- /** 只读账号口令;启动参数优先于环境变量,便于本机排查而不必改环境。 */
- static String credential(String variableName)
+ /**
+ * 按「本地凭据文件 → 环境变量 → 启动参数」取值;键名由实例配置的 {@code passwordEnv} 指定。
+ * 文件优先,是为了让部署只做"复制模板填一行"这一件事。
+ */
+ static String credential(String key, Path credentialsFile, Map<String, String> environment,
+ Function<String, String> startupParameters)
{
- if (variableName == null || variableName.isBlank())
- throw new DeviceAdapterException("未配置厂商库口令的取值变量名");
- String value = System.getenv(variableName);
- if (value == null || value.isBlank()) value = System.getProperty(variableName);
- if (value == null || value.isBlank())
- throw new DeviceAdapterException("缺少厂商库连接口令:请设置环境变量 " + variableName);
- return value;
+ if (key == null || key.isBlank()) throw new DeviceAdapterException("未配置厂商库口令的取值名");
+ String fromFile = credentialFromFile(key, credentialsFile);
+ if (fromFile != null) return fromFile;
+ String fromEnvironment = environment == null ? null : environment.get(key);
+ if (fromEnvironment != null && !fromEnvironment.isBlank()) return fromEnvironment.trim();
+ String fromParameter = startupParameters == null ? null : startupParameters.apply(key);
+ if (fromParameter != null && !fromParameter.isBlank()) return fromParameter.trim();
+ throw new DeviceAdapterException("缺少厂商库连接口令:" + credentialsFile
+ + " 中没有键 " + key + ",环境变量与启动参数 -D" + key + " 也都没有");
+ }
+
+ /** 凭据文件缺失不是错误:交付形态可能只用环境变量,所以这里只负责"读到了就返回"。 */
+ private static String credentialFromFile(String key, Path credentialsFile)
+ {
+ if (credentialsFile == null || !Files.isRegularFile(credentialsFile)) return null;
+ Properties properties = new Properties();
+ try (InputStream input = Files.newInputStream(credentialsFile))
+ {
+ properties.load(input);
+ }
+ catch (IOException exception)
+ {
+ throw new DeviceAdapterException("厂商库凭据文件无法读取:" + credentialsFile, exception);
+ }
+ String value = properties.getProperty(key);
+ return value == null || value.isBlank() ? null : value.trim();
}
/**
--
Gitblit v1.7.1