# 后端文件服务
**本文引用的文件**
- [FileController.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/FileController.java)
- [FileService.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/FileService.java)
- [FileStorageProperties.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/FileStorageProperties.java)
- [GlobalExceptionHandler.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/exception/GlobalExceptionHandler.java)
- [BusinessException.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/exception/BusinessException.java)
- [application.yaml](file://fms-api/src/main/resources/application.yaml)
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件为 FMS 后端文件服务的综合文档,聚焦于文件上传、下载、删除、预览等核心能力。内容涵盖:
- FileService 核心服务类的实现与数据流
- FileController 控制器的 RESTful API 设计
- FileStorageProperties 配置类支持的存储策略(本地文件系统与云存储 OSS)
- 安全机制(访问路径校验、类型与大小限制建议、权限上下文)
- API 调用示例与错误处理策略(含事务管理与异常处理)
## 项目结构
后端文件相关代码位于 fms-api 模块中,主要包含控制器、服务、配置与异常处理四类文件:
- 控制器:FileController 暴露文件操作的 HTTP 端点
- 服务:FileService 封装文件上传、删除、OSS 凭证获取、记录保存等业务逻辑
- 配置:FileStorageProperties 提供本地与 OSS 的存储策略配置
- 异常:GlobalExceptionHandler 统一捕获并返回标准化错误响应
```mermaid
graph TB
Client["客户端"] --> Ctrl["FileController
REST 接口"]
Ctrl --> Svc["FileService
业务逻辑"]
Svc --> Cfg["FileStorageProperties
存储配置"]
Svc --> DB["数据库
bf_files"]
Svc --> FS["本地文件系统"]
Svc --> OSS["OSS 网关
g3oss"]
```
**图表来源**
- [FileController.java:28-112](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/FileController.java#L28-L112)
- [FileService.java:51-266](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/FileService.java#L51-L266)
- [FileStorageProperties.java:5-68](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/FileStorageProperties.java#L5-L68)
**章节来源**
- [FileController.java:28-112](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/FileController.java#L28-L112)
- [FileService.java:34-266](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/FileService.java#L34-L266)
- [FileStorageProperties.java:5-68](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/FileStorageProperties.java#L5-L68)
## 核心组件
- FileController:定义 /file 命名空间下的 REST 接口,包括配置查询、本地上传、OSS 上传凭证、保存记录、删除、静态资源访问等。
- FileService:实现本地上传、OSS 凭证获取、记录保存、删除(本地/OSS)、DB 写入与清理等核心流程。
- FileStorageProperties:通过前缀 fms.file 绑定配置,支持 storageType、local.storageDir/urlPrefix、oss.g3ossUrl。
- GlobalExceptionHandler:统一捕获认证、业务、数据库及系统异常,返回 ApiResponse 标准格式。
**章节来源**
- [FileController.java:28-112](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/FileController.java#L28-L112)
- [FileService.java:34-266](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/FileService.java#L34-L266)
- [FileStorageProperties.java:5-68](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/FileStorageProperties.java#L5-L68)
- [GlobalExceptionHandler.java:15-84](file://fms-api/src/main/java/cn/g3soft/fmsapi/exception/GlobalExceptionHandler.java#L15-L84)
## 架构总览
文件服务采用“控制器-服务-存储”的分层架构:
- 控制器负责参数接收与响应包装
- 服务负责业务编排与存储适配(本地/OSS)
- 配置类决定运行时存储策略
- 异常处理器统一错误输出
```mermaid
sequenceDiagram
participant C as "客户端"
participant Ctrl as "FileController"
participant Svc as "FileService"
participant Cfg as "FileStorageProperties"
participant DB as "数据库"
participant FS as "本地文件系统"
participant OSS as "OSS 网关"
C->>Ctrl : POST /file/upload
Ctrl->>Svc : localUpload(files, father, moduleId, cateId)
Svc->>Cfg : 读取本地存储目录与URL前缀
Svc->>FS : 写入文件到 {orgId}/{yyyy}/{MM}/{dd}/文件名
Svc->>DB : 插入 bf_files 记录
Svc-->>Ctrl : 返回文件元数据列表
Ctrl-->>C : ApiResponse.success(列表)
```
**图表来源**
- [FileController.java:48-59](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/FileController.java#L48-L59)
- [FileService.java:51-96](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/FileService.java#L51-L96)
- [FileStorageProperties.java:36-55](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/FileStorageProperties.java#L36-L55)
## 详细组件分析
### FileController 控制器
- 职责
- 提供 /file/config 返回当前存储模式
- 提供 /file/upload 本地多文件上传
- 提供 /file/upload-credential 获取 OSS 上传凭证
- 提供 /file/save-record 保存文件记录(OSS 直传回调)
- 提供 /file/delete 删除文件
- 提供 /file/static/{fileName} 本地静态文件访问(内联预览)
- 关键点
- 使用统一的 ApiResponse 包装成功结果
- 静态文件访问包含路径穿越防护,仅允许在配置的本地存储目录下访问
- 删除操作委托给 FileService,由服务根据存储类型选择删除策略
```mermaid
flowchart TD
Start(["请求进入 /file/*"]) --> Route{"路由匹配"}
Route --> |/config| GetCfg["返回 storageType"]
Route --> |/upload| Upload["调用 FileService.localUpload"]
Route --> |/upload-credential| Cred["调用 FileService.ossCredential"]
Route --> |/save-record| Save["调用 FileService.saveRecord"]
Route --> |/delete| Del["调用 FileService.delete"]
Route --> |/static/{fileName}| Serve["读取本地文件并返回"]
GetCfg --> End(["返回 ApiResponse"])
Upload --> End
Cred --> End
Save --> End
Del --> End
Serve --> End
```
**图表来源**
- [FileController.java:28-112](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/FileController.java#L28-L112)
**章节来源**
- [FileController.java:28-112](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/FileController.java#L28-L112)
### FileService 服务
- 职责
- 本地上传:生成唯一文件名与子路径,落盘后写入 bf_files 表,返回元数据
- OSS 凭证:向 g3oss 网关请求上传凭证(bucket=机构码)
- 保存记录:将前端直传后的文件信息持久化到 bf_files
- 删除:根据存储类型删除本地文件或调用 OSS 网关删除,并删除 DB 记录
- 关键流程
- 本地上传:按 orgId/年/月/日 组织目录,避免冲突;URL 映射基于 urlPrefix + 相对路径
- 删除:先删存储再删 DB;OSS 删除时从 mapfilename 提取 objectName 并调用 g3oss 删除接口
- 数据库连接:通过 DataSourceUtils 获取与释放连接,确保资源正确回收
```mermaid
classDiagram
class FileService {
+localUpload(files, father, moduleId, cateId) Map[]
+saveRecord(meta) Map
+ossCredential() Map
+delete(subid) void
-insertFileRecord(...)
-deleteLocalFile(mapfilename)
-deleteOssFile(mapfilename)
-deleteDbRow(subid)
}
class FileStorageProperties {
+storageType : String
+local : Local
+oss : Oss
}
class DbUtils {
+loadData(table, where, cols, params) Map[]
}
FileService --> FileStorageProperties : "读取存储策略"
FileService --> DbUtils : "查询/删除记录"
```
**图表来源**
- [FileService.java:34-266](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/FileService.java#L34-L266)
- [FileStorageProperties.java:5-68](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/FileStorageProperties.java#L5-L68)
**章节来源**
- [FileService.java:51-266](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/FileService.java#L51-L266)
### FileStorageProperties 配置
- 配置前缀:fms.file
- 字段说明
- storageType:存储类型,如 local 或 aliyun-oss
- local.storageDir:本地文件根目录
- local.urlPrefix:本地文件访问 URL 前缀
- oss.g3ossUrl:OSS 网关地址(用于获取凭证与删除)
- 作用:驱动 FileService 在不同存储后端间切换
```mermaid
flowchart LR
A["application.yaml
fms.file.*"] --> B["FileStorageProperties"]
B --> C["FileService
选择本地/OSS"]
```
**图表来源**
- [FileStorageProperties.java:5-68](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/FileStorageProperties.java#L5-L68)
- [application.yaml](file://fms-api/src/main/resources/application.yaml)
**章节来源**
- [FileStorageProperties.java:5-68](file://fms-api/src/main/java/cn/g3soft/fmsapi/config/FileStorageProperties.java#L5-L68)
- [application.yaml](file://fms-api/src/main/resources/application.yaml)
### 安全机制
- 访问权限验证
- 通过 OrgContext 获取当前机构与用户上下文,用于目录隔离与审计字段填充
- 文件类型过滤
- 当前未在服务层做严格白名单校验;建议在控制器或服务层增加扩展名白名单校验
- 大小限制
- 当前未在服务层做文件大小限制;建议在控制器或服务层增加大小校验
- 路径穿越防护
- 静态文件访问时对解析路径进行规范化并校验是否在允许的根目录下,防止越权访问
**章节来源**
- [FileController.java:90-111](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/FileController.java#L90-L111)
- [FileService.java:63-96](file://fms-api/src/main/java/cn/g3soft/fmsapi/service/FileService.java#L63-L96)
### API 端点规范
- GET /file/config
- 功能:返回当前存储模式
- 响应:ApiResponse