06-文件管理 bams-file¶
📄 创建: ZCode AI 2026-08-14 · 修改: JimWb 2026-08-14
bams-file(61 个类)提供文件存储管理能力。当前主线是 StorageProvider 体系(支持本地 + RustFS 对象存储),旧版 FileClient 策略体系作为保留能力留存。
⚠️ 重要:两套存储体系¶
模块内存在两套并存的存储体系:
| 体系 | 状态 | 说明 |
|---|---|---|
| StorageProvider(新版/主推) | ✅ 当前生效 | RustFSFileController + SysFileStorageConfigController 使用。支持本地 + RustFS(S3兼容)。2026-07-12 引入 |
| FileClient(旧版/保留) | ⚠️ 孤儿代码 | 策略+工厂+5种后端(DB/Local/FTP/SFTP/S3),但已无 Controller 入口。2026-07-22 删除了入口 Controller |
本文档以新版 StorageProvider 为主线,旧版在末尾简要说明。
一、StorageProvider 体系(主线)¶
1.1 架构¶
RustFSFileController (REST 接口)
│
▼
StorageManager (门面 Facade,@Component)
│ resolve(key) 按 key 前缀路由
│ stripRoutingKey() 剥路由前缀
▼
StorageProvider (接口)
├── LocalStorageProvider (本地磁盘)
└── RustFSStorageProvider (S3 兼容对象存储)
1.2 StorageProvider 接口¶
cn.cnbm.bams.file.storage.StorageProvider
统一的流式存储抽象,基于 InputStream:
| 方法签名 | 功能 |
|---|---|
String upload(String key, InputStream, long contentLength, String contentType, String originalFilename) |
上传,返回存储 key |
boolean delete(String key) |
删除 |
InputStream download(String key) |
下载(调用方自行关流) |
String getPresignedUrl(String key, int expireMinutes) |
预签名 URL |
boolean exists(String key) |
是否存在 |
List<FileEntry> list(String prefix) |
列文件 |
FileEntry 内部类:bucket / key / size / lastModified / storageType / originalFilename
1.3 两个实现¶
LocalStorageProvider¶
cn.cnbm.bams.file.storage.impl.LocalStorageProvider
| 配置项 | 默认值 | 说明 |
|---|---|---|
localPath |
/data/upload |
存储根目录 |
localPrefix |
/statics |
URL 访问前缀 |
特点:
- 目录布局 {localPath}/{key}
- 原始文件名用 sidecar .meta 文件保存(<filename>.meta 存原名文本)
- resolveSafe() 路径穿越防护(非法 key 抛 BussinessException)
- getPresignedUrl 返回 localPrefix + "/" + key(本地无真正签名)
RustFSStorageProvider¶
cn.cnbm.bams.file.storage.impl.RustFSStorageProvider
RustFS 本质是 S3 兼容的对象存储(类似 MinIO 定位),用 AWS SDK v2 访问。纯 S3 兼容,换 MinIO/OSS/COS 同样可用。
| 配置项 | 默认值 | 说明 |
|---|---|---|
endpoint |
— | S3 端点 |
bucket |
— | 桶名 |
accessKey / secretKey |
— | 凭证 |
region |
cn-north-1 |
区域 |
pathStyle |
true |
路径风格访问 |
特点:
- 构造时 ensureBucket():自动探测/创建桶
- 原始文件名用 S3 Object Tagging 保存(x-amz-tagging: original-filename=<URL编码>)
- list() 用 ListObjectsV2 分页(maxKeys=1000)
- getPresignedUrl 用 S3Presigner 按分钟过期
1.4 StorageManager(核心门面)¶
cn.cnbm.bams.file.storage.StorageManager(@Component)
所有 Controller 只认它。特点:
| 能力 | 说明 |
|---|---|
| 路由机制 | 按上传 key 的第一段路径匹配。先查桶编码 → 再查路由键 → 默认兜底 |
| 双写 | storageType=RUSTFS 且 dualWrite=true 时,同时写 RustFS 和本地(降级副本) |
| 生命周期 | @PostConstruct init() 调 reload();@PreDestroy 关闭 RustFS 客户端 |
公开 API:
| 方法 | 功能 |
|---|---|
upload(key, in, size, contentType, 原名) |
上传 |
uploadDualWrite(key, rustfs流, 本地流, ...) |
双写上传 |
download(key) / download(key, routeKey) |
下载 |
delete(key) |
删除(RustFS+本地都删) |
list(prefix) |
列文件 |
getOriginalFilename(key) |
取原始文件名 |
getPresignedUrl(key, expireMinutes) |
预签名 URL |
getActiveConfig() |
当前生效配置 |
reload() |
重新加载配置 |
1.5 配置表 SysFileStorageConfig¶
cn.cnbm.bams.file.pojo.file.SysFileStorageConfig(表 pub_file_storage_config)
| 字段 | 类型 | 说明 |
|---|---|---|
storageType |
String | LOCAL 或 RUSTFS |
rustfsEndpoint |
String | RustFS 端点 |
rustfsAccessKey / rustfsSecretKey |
String | 凭证 |
rustfsBucket |
String | 桶名 |
rustfsRegion |
String | 区域 |
rustfsPathStyle |
Boolean | 路径风格 |
localPath |
String | 本地存储路径 |
localPrefix |
String | 本地 URL 前缀 |
dualWrite |
Boolean | 是否双写 |
enabled |
Boolean | 是否启用 |
routeKey |
String | 路由键(空串=默认兜底) |
corpCode |
String | 公司编码(多租户) |
1.6 上传/下载完整流程¶
上传 POST /file/rustfs/upload:
1. 校验文件非空
2. storageManager.getActiveConfig() 取生效配置
3. 拼 key:{bizType}/{yyyyMMdd}/{UUID}{ext}(bizType 默认 files)
4. 若 RUSTFS + dualWrite → uploadDualWrite()
否则 → upload()
5. 返回 {key, fileName, size, storageType, url(预签名60分钟)}
下载 GET /file/rustfs/download/{*key}:
storageManager.download(key) → 流拷贝到 response
文件名优先用 getOriginalFilename()(本地读 .meta / RustFS 读 tagging)
其他接口:
| 接口 | 方法 | 功能 |
|---|---|---|
/file/rustfs/upload |
POST | 上传 |
/file/rustfs/download/{*key} |
GET | 下载 |
/file/rustfs/delete |
POST | 删除 |
/file/rustfs/list |
GET | 列文件 |
/file/rustfs/page |
POST | 分页(内存分页) |
/file/rustfs/preview/{*key} |
GET | 预览(POI 把 ppt 每页渲染成 base64 PNG) |
/file/rustfs/config |
GET | 当前生效配置 |
/file/storageConfig/reload |
POST | 重载 StorageManager |
/file/storageConfig/testConnection |
POST | 测试 RustFS 连通 |
SysFileStorageConfigController继承EnergyBaseController,提供存储配置的 CRUD。
二、FileClient 策略体系(旧版/保留能力)¶
⚠️ 当前无 Controller 入口。设计本身是教科书级的策略+工厂+模板方法,源码保留完好,但 2026-07-22 删除了入口 Controller 后成为孤儿。了解即可,不要在新代码中使用。
设计模式¶
FileClient (接口)
│
AbstractFileClient<Config> (模板方法基类)
│
├── DBFileClient (数据库存储)
├── LocalFileClient (本地磁盘)
├── FtpFileClient (FTP)
├── SftpFileClient (SFTP)
└── S3FileClient (S3 兼容,支持 MinIO/OSS/COS 等)
FileClientFactory (工厂,反射创建实例)
FileStorageEnum (注册表,5 种类型)
FileStorageEnum 枚举¶
| 枚举 | storage | 客户端类 | 支持桶操作 |
|---|---|---|---|
| DB | 1 | DBFileClient | ❌ 空实现 |
| LOCAL | 10 | LocalFileClient | ❌ 空实现 |
| FTP | 11 | FtpFileClient | ❌ 空实现 |
| SFTP | 12 | SftpFileClient | ❌ 空实现 |
| S3 | 20 | S3FileClient | ✅ 真正实现 |
只有 S3FileClient 真正实现了桶操作(createBucket),其他四种的桶方法是空实现。
FileAutoConfiguration¶
@Configuration(proxyBeanMethods = false),只装配一个 Bean:FileClientFactory。仅服务于旧体系。
三、Excel 转换器¶
⚠️ 半成品:DictConvert 和 AreaConvert 的实际查询逻辑被注释/TODO 掉,目前只有 MoneyConvert/JsonConvert 可直接用。详见 12-FAQ与注意事项。
基于 FastExcel(原 EasyExcel)的 Converter 实现,用于 Excel 导入导出的字段转换。
| 转换器 | 功能 | 状态 |
|---|---|---|
MoneyConvert |
金额 分→元(导出时 /100 保留 2 位) | ✅ 可用 |
JsonConvert |
对象→JSON 串(导出) | ✅ 可用 |
DictConvert |
字典 label↔value(配合 @DictFormat) |
⚠️ 查询逻辑被 TODO 注释 |
AreaConvert |
地区名→编号 | ⚠️ 解析逻辑被注释 |
注解¶
| 注解 | 说明 |
|---|---|
@DictFormat("字典类型") |
字段级,配合 DictConvert 指定字典类型 |
@ExcelColumnSelect |
字段级,给 Excel 列加下拉(dictType 或 functionName 二选一) |
四、其他组件¶
FileTypeUtils¶
cn.cnbm.bams.file.service.core.utils.FileTypeUtils
基于 Apache Tika 的 MIME 类型识别。
| 方法 | 功能 |
|---|---|
getMineType(byte[] data) / getMineType(String name) |
识别 MIME 类型 |
getExtension(String mimeType) |
mimeType→后缀 |
writeAttachment(response, ...) |
写 HTTP 附件响应(含 video Content-Range 兼容) |
数据表¶
| 表 | 实体 | 说明 |
|---|---|---|
pub_file |
FileDO | 文件记录 |
pub_file_config |
FileConfigDO | 文件配置(旧版) |
pub_file_content |
FileContentDO | DB 存储内容(旧版) |
pub_file_storage_config |
SysFileStorageConfig | 存储配置(新版) |
相关文档¶
- 01-快速开始 — Maven 依赖引入
- 09-通用功能 — EnergyBaseController(文件 Controller 继承它)
- 12-FAQ与注意事项 — 旧版 FileClient 无入口、Excel 转换器半成品