Files
workspace/code/fms/.qoder/repowiki/zh/content/API接口文档/文件接口.md
T
2026-08-23 21:02:41 +08:00

14 KiB
Raw Blame History

文件接口

**本文引用的文件** - [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) - [application.yaml](file://fms-api/src/main/resources/application.yaml) - [fileService.js](file://fms-vue/src/services/fileService.js)

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能考虑
  8. 故障排查指南
  9. 结论
  10. 附录

简介

本文件面向FMS系统的“文件接口”,提供统一的RESTful API,用于文件的上传、下载(预览)、删除与配置查询。系统支持两种存储模式:本地磁盘与阿里云OSS(通过g3oss服务)。前端会根据后端返回的存储类型自动选择上传路径,并在OSS模式下实现直传与凭证缓存,减少服务端压力。

项目结构

  • 控制器层:暴露 /api/file/* 端点,负责接收请求、参数校验与响应封装。
  • 服务层:封装本地/ OSS 上传、记录持久化、删除等核心逻辑。
  • 配置层:集中管理存储类型、本地存储目录、URL前缀、OSS地址等。
  • 前端服务:根据后端配置动态切换上传策略,封装批量上传、预览链接生成、删除等操作。
graph TB
Client["前端应用"] --> API["/api/file/* 控制器"]
API --> Svc["FileService 服务"]
Svc --> Local["本地文件系统"]
Svc --> DB["数据库 bf_files"]
Svc --> G3OSS["g3oss 服务(阿里云OSS代理)"]

图表来源

章节来源

核心组件

  • FileController:定义文件相关API端点,包括配置查询、上传、凭证获取、保存记录、删除、静态资源访问。
  • FileService:实现本地/ OSS 上传流程、DB记录写入、删除逻辑(含本地与OSS),以及OSS凭证转发。
  • FileStorageProperties:绑定 application.yaml 中 fms.file.* 配置项,控制存储行为。
  • fileService.js(前端):封装上传策略选择、批量上传、OSS直传、凭证缓存、预览链接生成与删除调用。

章节来源

架构总览

系统采用前后端分离架构,后端统一暴露文件接口,前端根据后端返回的存储类型自动选择上传方式。本地模式由后端直接落盘并写库;OSS模式由前端直传到g3oss,再回调后端保存记录。

sequenceDiagram
participant FE as "前端"
participant CTRL as "FileController"
participant SVC as "FileService"
participant FS as "本地文件系统"
participant DB as "数据库"
participant G3 as "g3oss(OSS)"
Note over FE,CTRL : 本地上传流程
FE->>CTRL : POST /api/file/upload (files, father, moduleId, cateId)
CTRL->>SVC : localUpload(files, ...)
loop 逐个文件
SVC->>FS : 写入磁盘(按 orgId/yyyy/MM/dd/)
SVC->>DB : INSERT bf_files
end
SVC-->>CTRL : 文件元数据列表
CTRL-->>FE : 成功响应
Note over FE,G3 : OSS直传流程
FE->>CTRL : POST /api/file/upload-credential
CTRL->>SVC : ossCredential()
SVC->>G3 : 获取上传凭证
G3-->>SVC : 凭证
SVC-->>CTRL : 凭证
CTRL-->>FE : 凭证
FE->>G3 : XHR 直传文件
FE->>CTRL : POST /api/file/save-record (记录)
CTRL->>SVC : saveRecord(...)
SVC->>DB : INSERT bf_files
SVC-->>CTRL : 结果
CTRL-->>FE : 成功响应

图表来源

详细组件分析

RESTful API 端点清单

  • 查询存储配置

    • 方法:POST
    • 路径:/api/file/config
    • 说明:返回当前存储类型 storageType(local 或 aliyun-oss)
    • 请求体:无
    • 响应:包含 storageType 的对象
  • 本地上传(多文件)

    • 方法:POST
    • 路径:/api/file/upload
    • 说明:使用 FormData,key 为 files;同时传入 father、moduleId、可选 cateId
    • 请求体:multipart/form-data
    • 响应:文件元数据列表(包含 subid、文件名、大小、扩展名、映射路径、模块ID、分类ID等)
  • 获取OSS上传凭证

    • 方法:POST
    • 路径:/api/file/upload-credential
    • 说明:后端转发到 g3oss 获取凭证,bucket=机构码
    • 请求体:无
    • 响应:包含 accessid、policy、signature、dir、host 等
  • 保存文件记录(OSS直传后回调)

    • 方法:POST
    • 路径:/api/file/save-record
    • 说明:前端直传成功后回调,写入 bf_files
    • 请求体:包含 subid、father、mx_moduleid、mx_cate_id、mx_filename、mx_filesize、mx_fileext、mx_mapfilename
    • 响应:保存结果
  • 删除文件

    • 方法:POST
    • 路径:/api/file/delete
    • 说明:根据 subid 删除存储文件与数据库记录
    • 请求体:{ subid }
    • 响应:成功空对象
  • 本地文件访问(预览/下载)

    • 方法:GET
    • 路径:/api/file/static/{fileName}
    • 说明:读取本地磁盘文件并以流形式返回,设置 inline 内容处置头
    • 路径参数:fileName(包含子目录:orgId/yyyy/MM/dd/文件名)
    • 响应:文件二进制流

章节来源

数据模型与字段说明

  • 文件记录表 bf_files(写入字段)
    • subid:文件唯一标识(雪花ID)
    • father:父级ID(可为空)
    • mx_filename:原始文件名
    • mx_filesize:文件大小(字节)
    • mx_fileext:扩展名(小写)
    • mx_mapfilename:映射路径或URL(本地为相对路径,OSS为完整URL)
    • mx_moduleid:所属模块ID(可为空)
    • mx_cate_id:分类ID(可为空)
    • mx_xh:排序号(默认0)
    • mx_sh:审核状态(默认0)
    • mx_inputuser_id:录入人ID
    • mx_inputdatetime:录入时间

章节来源

存储配置与扩展

  • 配置文件位置:application.yaml 中 fms.file.*
  • 关键配置项
    • storage-type:存储类型,可选 local 或 aliyun-oss
    • local.storage-dir:本地存储根目录
    • local.url-prefix:本地文件访问URL前缀
    • oss.g3oss-url:g3oss服务地址(用于获取凭证与删除)
  • 扩展方式
    • 新增存储类型:在 FileStorageProperties 增加对应配置类,并在 FileService 中扩展处理分支
    • 自定义URL生成规则:调整 local.url-prefix 或在服务层拼接
    • 鉴权与限流:可在控制器层增加拦截器或网关策略

章节来源

权限与安全

  • 路径穿越防护:本地文件访问时对解析路径进行规范化校验,确保不越出存储根目录
  • 上下文信息:文件写入时从 OrgContext 获取当前机构与用户ID,用于归属与审计
  • 凭证安全:OSS凭证由后端转发获取,前端仅持有临时凭证,避免直接暴露密钥

章节来源

前端集成要点

  • 初始化存储模式:调用 /api/file/config 获取 storageType
  • 批量上传:
    • 本地模式:构造 FormData,files key 追加多个文件,一次性提交
    • OSS模式:先获取凭证,然后逐个XHR直传到g3oss,最后回调 /api/file/save-record 写入记录
  • 预览链接:直接使用文件记录的 mx_mapfilename
  • 删除文件:调用 /api/file/delete,传入 subid
  • 凭证缓存:前端对OSS凭证进行缓存,避免频繁请求

章节来源

依赖关系分析

  • 控制器依赖服务层,服务层依赖配置与数据库工具,必要时调用外部g3oss服务
  • 前端依赖后端配置以决定上传策略,并在OSS模式下直传至g3oss
classDiagram
class FileController {
+config()
+upload()
+uploadCredential()
+saveRecord()
+delete()
+serveFile()
}
class FileService {
+localUpload()
+saveRecord()
+ossCredential()
+delete()
}
class FileStorageProperties {
+storageType
+local
+oss
}
class DbUtils
class OrgContext
FileController --> FileService : "调用"
FileService --> FileStorageProperties : "读取配置"
FileService --> DbUtils : "读写数据库"
FileService --> OrgContext : "获取上下文"

图表来源

章节来源

性能考虑

  • 本地上传:后端逐个写盘并插入记录,适合中小文件;大文件建议启用OSS直传以降低带宽与内存占用
  • OSS直传:前端直传g3oss,减少后端IO与网络开销;凭证缓存减少重复请求
  • 数据库连接:使用连接池配置,合理设置最大活动连接数与等待时间
  • 并发与限流:可根据业务场景在后端或网关层增加限流策略

[本节为通用指导,不直接分析具体文件]

故障排查指南

  • 本地文件访问404:检查路径是否规范且未发生穿越;确认存储目录与URL前缀配置正确
  • OSS凭证失败:检查 g3oss-url 可达性与返回状态码;确认机构上下文有效
  • 删除失败:确认 subid 存在;检查本地文件是否存在;OSS删除需确认 objectName 提取正确
  • 上传记录不一致:OSS直传成功后务必回调 save-record;若失败需重试或补偿

章节来源

结论

FMS文件接口提供了统一的文件管理能力,支持本地与OSS双模式,具备基本的安全防护与上下文感知能力。前端通过配置驱动自动选择上传策略,兼顾易用性与性能。后续可按需扩展新的存储后端或增强权限控制。

[本节为总结性内容,不直接分析具体文件]

附录

典型调用示例(步骤说明)

  • 多文件本地上传
    • 前端构造 FormData,append files、father、moduleId、cateId
    • 调用 POST /api/file/upload
    • 返回文件元数据列表,可用于展示与预览
  • OSS直传与进度跟踪
    • 调用 POST /api/file/upload-credential 获取凭证
    • 使用 XHR 逐个直传到 g3oss,可监听 loadprogress 事件实现进度条
    • 直传成功后调用 POST /api/file/save-record 写入记录
  • 预览链接生成
    • 直接使用文件记录的 mx_mapfilename
  • 删除文件
    • 调用 POST /api/file/delete,传入 subid

章节来源

流程图:本地文件访问

flowchart TD
Start(["进入 serveFile"]) --> Resolve["解析 fileName 并规范化路径"]
Resolve --> Check{"路径合法且在存储根目录下?"}
Check --> |否| NotFound["返回 404"]
Check --> |是| Serve["设置响应头并输出文件流"]
Serve --> End(["结束"])

图表来源