You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
425 lines
22 KiB
425 lines
22 KiB
|
1 month ago
|
# 文件上传下载
|
||
|
|
|
||
|
|
<cite>
|
||
|
|
**本文引用的文件**
|
||
|
|
- [FileController.java](file://crm-file/src/main/java/com/crm/file/controller/FileController.java)
|
||
|
|
- [FileApi.java](file://crm-file/src/main/java/com/crm/file/api/FileApi.java)
|
||
|
|
- [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java)
|
||
|
|
- [FileInfoServiceImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileInfoServiceImpl.java)
|
||
|
|
- [IFileInfoService.java](file://crm-file/src/main/java/com/crm/file/service/IFileInfoService.java)
|
||
|
|
- [FileInfo.java](file://crm-file/src/main/java/com/crm/file/domain/entity/FileInfo.java)
|
||
|
|
- [MultipartInitDTO.java](file://crm-file/src/main/java/com/crm/file/domain/dto/MultipartInitDTO.java)
|
||
|
|
- [UploadSession.java](file://crm-file/src/main/java/com/crm/file/domain/dto/UploadSession.java)
|
||
|
|
- [FileDownloadDTO.java](file://crm-file/src/main/java/com/crm/file/domain/dto/FileDownloadDTO.java)
|
||
|
|
- [FileInfoDTO.java](file://crm-file/src/main/java/com/crm/file/domain/dto/FileInfoDTO.java)
|
||
|
|
- [MinioConfig.java](file://crm-file/src/main/java/com/crm/file/config/MinioConfig.java)
|
||
|
|
- [FileProperties.java](file://crm-file/src/main/java/com/crm/file/config/FileProperties.java)
|
||
|
|
- [SchedulingConfig.java](file://crm-file/src/main/java/com/crm/file/config/SchedulingConfig.java)
|
||
|
|
- [OrphanChunkCleanupTask.java](file://crm-file/src/main/java/com/crm/file/task/OrphanChunkCleanupTask.java)
|
||
|
|
- [Result.java](file://crm-base/src/main/java/com/crm/base/domain/result/Result.java)
|
||
|
|
- [ResultCodeEnum.java](file://crm-base/src/main/java/com/crm/base/domain/result/ResultCodeEnum.java)
|
||
|
|
- [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java)
|
||
|
|
- [SecurityUtils.java](file://crm-base/src/main/java/com/crm/base/security/SecurityUtils.java)
|
||
|
|
- [application.yml](file://crm-app/src/main/resources/application.yml)
|
||
|
|
</cite>
|
||
|
|
|
||
|
|
## 目录
|
||
|
|
1. [简介](#简介)
|
||
|
|
2. [项目结构](#项目结构)
|
||
|
|
3. [核心组件](#核心组件)
|
||
|
|
4. [架构总览](#架构总览)
|
||
|
|
5. [详细组件分析](#详细组件分析)
|
||
|
|
6. [依赖关系分析](#依赖关系分析)
|
||
|
|
7. [性能考量](#性能考量)
|
||
|
|
8. [故障排查指南](#故障排查指南)
|
||
|
|
9. [结论](#结论)
|
||
|
|
10. [附录:API 接口规范与示例](#附录api-接口规范与示例)
|
||
|
|
|
||
|
|
## 简介
|
||
|
|
本技术文档围绕文件上传下载能力,系统性阐述单文件上传、分片上传与断点续传的实现机制,覆盖 MultipartFile 处理流程、会话管理、进度跟踪、并发控制、重试与异常恢复策略,以及文件校验规则(大小限制、类型验证等)与安全机制。同时提供完整的 API 接口规范、请求响应示例和错误处理方案,并给出客户端集成建议与最佳实践。
|
||
|
|
|
||
|
|
## 项目结构
|
||
|
|
文件模块位于 crm-file 子模块中,采用分层设计:
|
||
|
|
- Controller 层:对外暴露 REST 接口,统一返回 Result 包装体
|
||
|
|
- Service 层:封装业务逻辑,协调存储与元数据服务
|
||
|
|
- Domain 层:实体与 DTO,承载上传会话、文件信息、下载参数等
|
||
|
|
- Config 层:MinIO 存储配置、文件大小限制、调度任务开关等
|
||
|
|
- Task 层:清理孤立分片的定时任务
|
||
|
|
- Base 模块:统一的异常处理、结果封装、安全工具等
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
graph TB
|
||
|
|
Client["客户端"] --> FC["FileController<br/>REST 接口"]
|
||
|
|
FC --> FA["FileApi<br/>抽象接口"]
|
||
|
|
FA --> FAI["FileApiImpl<br/>实现类"]
|
||
|
|
FAI --> FS["IFileInfoService / FileInfoServiceImpl<br/>元数据服务"]
|
||
|
|
FAI --> MINIO["MinIO 存储<br/>MinioConfig"]
|
||
|
|
FAI --> TASK["OrphanChunkCleanupTask<br/>分片清理"]
|
||
|
|
FS --> DB["数据库<br/>FileInfoMapper"]
|
||
|
|
FC --> RESULT["Result / ResultCodeEnum<br/>统一响应"]
|
||
|
|
FC --> EXC["GlobalExceptionHandlerAdvice<br/>全局异常处理"]
|
||
|
|
```
|
||
|
|
|
||
|
|
图表来源
|
||
|
|
- [FileController.java](file://crm-file/src/main/java/com/crm/file/controller/FileController.java)
|
||
|
|
- [FileApi.java](file://crm-file/src/main/java/com/crm/file/api/FileApi.java)
|
||
|
|
- [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java)
|
||
|
|
- [IFileInfoService.java](file://crm-file/src/main/java/com/crm/file/service/IFileInfoService.java)
|
||
|
|
- [FileInfoServiceImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileInfoServiceImpl.java)
|
||
|
|
- [MinioConfig.java](file://crm-file/src/main/java/com/crm/file/config/MinioConfig.java)
|
||
|
|
- [OrphanChunkCleanupTask.java](file://crm-file/src/main/java/com/crm/file/task/OrphanChunkCleanupTask.java)
|
||
|
|
- [Result.java](file://crm-base/src/main/java/com/crm/base/domain/result/Result.java)
|
||
|
|
- [ResultCodeEnum.java](file://crm-base/src/main/java/com/crm/base/domain/result/ResultCodeEnum.java)
|
||
|
|
- [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java)
|
||
|
|
|
||
|
|
章节来源
|
||
|
|
- [FileController.java](file://crm-file/src/main/java/com/crm/file/controller/FileController.java)
|
||
|
|
- [FileApi.java](file://crm-file/src/main/java/com/crm/file/api/FileApi.java)
|
||
|
|
- [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java)
|
||
|
|
- [FileInfoServiceImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileInfoServiceImpl.java)
|
||
|
|
- [MinioConfig.java](file://crm-file/src/main/java/com/crm/file/config/MinioConfig.java)
|
||
|
|
- [SchedulingConfig.java](file://crm-file/src/main/java/com/crm/file/config/SchedulingConfig.java)
|
||
|
|
- [OrphanChunkCleanupTask.java](file://crm-file/src/main/java/com/crm/file/task/OrphanChunkCleanupTask.java)
|
||
|
|
- [Result.java](file://crm-base/src/main/java/com/crm/base/domain/result/Result.java)
|
||
|
|
- [ResultCodeEnum.java](file://crm-base/src/main/java/com/crm/base/domain/result/ResultCodeEnum.java)
|
||
|
|
- [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java)
|
||
|
|
|
||
|
|
## 核心组件
|
||
|
|
- FileController:定义上传、分片上传、断点续传、下载、进度查询等 REST 端点,统一使用 Result 包装响应
|
||
|
|
- FileApi / FileApiImpl:上传下载的核心业务编排,包含分片初始化、分片合并、元数据持久化、存储对象操作
|
||
|
|
- IFileInfoService / FileInfoServiceImpl:文件元数据的增删改查,维护 FileInfo 实体与数据库映射
|
||
|
|
- MinioConfig / FileProperties:MinIO 连接参数、桶名、访问密钥、文件大小限制、分片大小等配置
|
||
|
|
- OrphanChunkCleanupTask:定时扫描并清理长时间未完成的孤立分片,释放存储空间
|
||
|
|
- Result / ResultCodeEnum / GlobalExceptionHandlerAdvice:统一响应体、错误码、全局异常捕获与转换
|
||
|
|
|
||
|
|
章节来源
|
||
|
|
- [FileController.java](file://crm-file/src/main/java/com/crm/file/controller/FileController.java)
|
||
|
|
- [FileApi.java](file://crm-file/src/main/java/com/crm/file/api/FileApi.java)
|
||
|
|
- [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java)
|
||
|
|
- [IFileInfoService.java](file://crm-file/src/main/java/com/crm/file/service/IFileInfoService.java)
|
||
|
|
- [FileInfoServiceImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileInfoServiceImpl.java)
|
||
|
|
- [MinioConfig.java](file://crm-file/src/main/java/com/crm/file/config/MinioConfig.java)
|
||
|
|
- [FileProperties.java](file://crm-file/src/main/java/com/crm/file/config/FileProperties.java)
|
||
|
|
- [OrphanChunkCleanupTask.java](file://crm-file/src/main/java/com/crm/file/task/OrphanChunkCleanupTask.java)
|
||
|
|
- [Result.java](file://crm-base/src/main/java/com/crm/base/domain/result/Result.java)
|
||
|
|
- [ResultCodeEnum.java](file://crm-base/src/main/java/com/crm/base/domain/result/ResultCodeEnum.java)
|
||
|
|
- [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java)
|
||
|
|
|
||
|
|
## 架构总览
|
||
|
|
整体采用“控制器-服务-存储”的分层架构,结合 MinIO 作为对象存储,元数据落库,分片上传通过会话管理保证可靠性与可恢复性。
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
sequenceDiagram
|
||
|
|
participant C as "客户端"
|
||
|
|
participant FC as "FileController"
|
||
|
|
participant FA as "FileApiImpl"
|
||
|
|
participant FS as "FileInfoServiceImpl"
|
||
|
|
participant MINIO as "MinIO"
|
||
|
|
participant DB as "数据库"
|
||
|
|
C->>FC : "POST /upload/init (分片初始化)"
|
||
|
|
FC->>FA : "initMultipart(params)"
|
||
|
|
FA->>MINIO : "创建分片桶/命名空间"
|
||
|
|
FA-->>C : "返回 uploadId/sessionId"
|
||
|
|
loop "分片上传"
|
||
|
|
C->>FC : "POST /upload/chunk (携带分片数据)"
|
||
|
|
FC->>FA : "uploadChunk(uploadId, chunkIndex, data)"
|
||
|
|
FA->>MINIO : "PUT Object(分片)"
|
||
|
|
FA-->>C : "返回分片状态"
|
||
|
|
end
|
||
|
|
C->>FC : "POST /upload/complete (完成合并)"
|
||
|
|
FC->>FA : "completeMultipart(uploadId, chunks)"
|
||
|
|
FA->>MINIO : "合并分片为完整对象"
|
||
|
|
FA->>FS : "保存 FileInfo 元数据"
|
||
|
|
FS->>DB : "INSERT/UPDATE FileInfo"
|
||
|
|
FA-->>C : "返回文件ID/URL"
|
||
|
|
C->>FC : "GET /download/{fileId}"
|
||
|
|
FC->>FA : "download(fileId)"
|
||
|
|
FA->>FS : "查询 FileInfo"
|
||
|
|
FS->>DB : "SELECT FileInfo"
|
||
|
|
FA->>MINIO : "GetObject(流式下载)"
|
||
|
|
FA-->>C : "返回文件流"
|
||
|
|
```
|
||
|
|
|
||
|
|
图表来源
|
||
|
|
- [FileController.java](file://crm-file/src/main/java/com/crm/file/controller/FileController.java)
|
||
|
|
- [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java)
|
||
|
|
- [FileInfoServiceImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileInfoServiceImpl.java)
|
||
|
|
- [MinioConfig.java](file://crm-file/src/main/java/com/crm/file/config/MinioConfig.java)
|
||
|
|
|
||
|
|
## 详细组件分析
|
||
|
|
|
||
|
|
### 单文件上传流程(MultipartFile)
|
||
|
|
- 入口:FileController 接收 MultipartFile 参数
|
||
|
|
- 校验:基于 FileProperties 的大小限制与类型白名单进行校验
|
||
|
|
- 存储:调用 FileApiImpl 将文件写入 MinIO,生成唯一对象键
|
||
|
|
- 元数据:FileInfoServiceImpl 持久化文件元数据(名称、大小、类型、路径等)
|
||
|
|
- 响应:统一 Result 包装成功或错误信息
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
flowchart TD
|
||
|
|
Start(["开始"]) --> Validate["校验文件大小/类型"]
|
||
|
|
Validate --> |通过| SaveToMinIO["写入 MinIO"]
|
||
|
|
Validate --> |失败| Error["返回错误码"]
|
||
|
|
SaveToMinIO --> PersistMeta["持久化 FileInfo"]
|
||
|
|
PersistMeta --> Return["返回 Result{fileId,url}"]
|
||
|
|
Error --> End(["结束"])
|
||
|
|
Return --> End
|
||
|
|
```
|
||
|
|
|
||
|
|
图表来源
|
||
|
|
- [FileController.java](file://crm-file/src/main/java/com/crm/file/controller/FileController.java)
|
||
|
|
- [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java)
|
||
|
|
- [FileInfoServiceImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileInfoServiceImpl.java)
|
||
|
|
- [FileProperties.java](file://crm-file/src/main/java/com/crm/file/config/FileProperties.java)
|
||
|
|
|
||
|
|
章节来源
|
||
|
|
- [FileController.java](file://crm-file/src/main/java/com/crm/file/controller/FileController.java)
|
||
|
|
- [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java)
|
||
|
|
- [FileInfoServiceImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileInfoServiceImpl.java)
|
||
|
|
- [FileProperties.java](file://crm-file/src/main/java/com/crm/file/config/FileProperties.java)
|
||
|
|
|
||
|
|
### 分片上传与断点续传
|
||
|
|
- 初始化:客户端调用初始化接口获取 uploadId/sessionId,服务端建立分片会话
|
||
|
|
- 分片上传:客户端按序或乱序上传分片,服务端记录已上传分片索引
|
||
|
|
- 断点续传:支持重复上传同一分片,服务端幂等处理;未完成会话可继续补传
|
||
|
|
- 合并完成:所有分片上传完成后触发合并,生成最终对象并更新元数据
|
||
|
|
- 进度跟踪:可通过 session 查询各分片上传状态,计算总体进度
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
classDiagram
|
||
|
|
class UploadSession {
|
||
|
|
+string sessionId
|
||
|
|
+string uploadId
|
||
|
|
+long fileSize
|
||
|
|
+int chunkSize
|
||
|
|
+Set~Integer~ uploadedChunks
|
||
|
|
+boolean completed
|
||
|
|
+timestamp createdAt
|
||
|
|
+timestamp updatedAt
|
||
|
|
}
|
||
|
|
class FileInfo {
|
||
|
|
+string id
|
||
|
|
+string name
|
||
|
|
+long size
|
||
|
|
+string type
|
||
|
|
+string storageKey
|
||
|
|
+string url
|
||
|
|
+timestamp createdAt
|
||
|
|
+timestamp updatedAt
|
||
|
|
}
|
||
|
|
class FileApiImpl {
|
||
|
|
+initMultipart(params) UploadSession
|
||
|
|
+uploadChunk(uploadId, index, data) boolean
|
||
|
|
+completeMultipart(uploadId, chunks) FileInfo
|
||
|
|
-validateChunk(index, size) boolean
|
||
|
|
-mergeChunks(uploadId) void
|
||
|
|
}
|
||
|
|
class FileInfoServiceImpl {
|
||
|
|
+saveFileInfo(info) FileInfo
|
||
|
|
+getFileInfo(id) FileInfo
|
||
|
|
+updateFileInfo(id, info) FileInfo
|
||
|
|
}
|
||
|
|
FileApiImpl --> UploadSession : "创建/维护"
|
||
|
|
FileApiImpl --> FileInfoServiceImpl : "持久化元数据"
|
||
|
|
FileInfoServiceImpl --> FileInfo : "CRUD"
|
||
|
|
```
|
||
|
|
|
||
|
|
图表来源
|
||
|
|
- [UploadSession.java](file://crm-file/src/main/java/com/crm/file/domain/dto/UploadSession.java)
|
||
|
|
- [FileInfo.java](file://crm-file/src/main/java/com/crm/file/domain/entity/FileInfo.java)
|
||
|
|
- [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java)
|
||
|
|
- [FileInfoServiceImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileInfoServiceImpl.java)
|
||
|
|
|
||
|
|
章节来源
|
||
|
|
- [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java)
|
||
|
|
- [UploadSession.java](file://crm-file/src/main/java/com/crm/file/domain/dto/UploadSession.java)
|
||
|
|
- [FileInfo.java](file://crm-file/src/main/java/com/crm/file/domain/entity/FileInfo.java)
|
||
|
|
- [FileInfoServiceImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileInfoServiceImpl.java)
|
||
|
|
|
||
|
|
### 下载流程
|
||
|
|
- 入口:FileController 接收 fileId 或下载参数
|
||
|
|
- 校验:检查权限与文件存在性
|
||
|
|
- 读取:从 MinIO 流式读取对象内容
|
||
|
|
- 响应:以流形式返回,设置合适的 Content-Type 与文件名
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
sequenceDiagram
|
||
|
|
participant C as "客户端"
|
||
|
|
participant FC as "FileController"
|
||
|
|
participant FA as "FileApiImpl"
|
||
|
|
participant FS as "FileInfoServiceImpl"
|
||
|
|
participant MINIO as "MinIO"
|
||
|
|
C->>FC : "GET /download?fileId=xxx"
|
||
|
|
FC->>FA : "download(fileId)"
|
||
|
|
FA->>FS : "查询 FileInfo"
|
||
|
|
FS-->>FA : "返回 FileInfo"
|
||
|
|
FA->>MINIO : "GetObject(storageKey)"
|
||
|
|
MINIO-->>FA : "返回输入流"
|
||
|
|
FA-->>C : "返回文件流"
|
||
|
|
```
|
||
|
|
|
||
|
|
图表来源
|
||
|
|
- [FileController.java](file://crm-file/src/main/java/com/crm/file/controller/FileController.java)
|
||
|
|
- [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java)
|
||
|
|
- [FileInfoServiceImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileInfoServiceImpl.java)
|
||
|
|
- [MinioConfig.java](file://crm-file/src/main/java/com/crm/file/config/MinioConfig.java)
|
||
|
|
|
||
|
|
章节来源
|
||
|
|
- [FileController.java](file://crm-file/src/main/java/com/crm/file/controller/FileController.java)
|
||
|
|
- [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java)
|
||
|
|
- [FileInfoServiceImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileInfoServiceImpl.java)
|
||
|
|
|
||
|
|
### 会话管理与进度跟踪
|
||
|
|
- 会话模型:UploadSession 记录 sessionId、uploadId、分片集合、完成状态、时间戳
|
||
|
|
- 进度计算:根据已上传分片数量与总分片数计算百分比
|
||
|
|
- 并发控制:分片上传允许乱序到达,服务端以分片索引去重
|
||
|
|
- 超时清理:OrphanChunkCleanupTask 定期清理长时间未完成的会话与分片
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
flowchart TD
|
||
|
|
Init["初始化会话"] --> Upload["上传分片"]
|
||
|
|
Upload --> Track{"是否全部上传?"}
|
||
|
|
Track --> |否| Upload
|
||
|
|
Track --> |是| Merge["合并分片"]
|
||
|
|
Merge --> Complete["标记会话完成"]
|
||
|
|
Complete --> Cleanup["定时清理孤立会话"]
|
||
|
|
```
|
||
|
|
|
||
|
|
图表来源
|
||
|
|
- [UploadSession.java](file://crm-file/src/main/java/com/crm/file/domain/dto/UploadSession.java)
|
||
|
|
- [OrphanChunkCleanupTask.java](file://crm-file/src/main/java/com/crm/file/task/OrphanChunkCleanupTask.java)
|
||
|
|
|
||
|
|
章节来源
|
||
|
|
- [UploadSession.java](file://crm-file/src/main/java/com/crm/file/domain/dto/UploadSession.java)
|
||
|
|
- [OrphanChunkCleanupTask.java](file://crm-file/src/main/java/com/crm/file/task/OrphanChunkCleanupTask.java)
|
||
|
|
|
||
|
|
### 文件校验与安全机制
|
||
|
|
- 大小限制:通过 FileProperties 配置最大文件大小,防止超大文件导致内存溢出
|
||
|
|
- 类型验证:白名单校验 MIME 类型或扩展名,拒绝非法类型
|
||
|
|
- 权限控制:结合 SecurityUtils 获取当前用户上下文,确保上传/下载权限
|
||
|
|
- 异常处理:GlobalExceptionHandlerAdvice 统一捕获并转换为标准错误码
|
||
|
|
|
||
|
|
章节来源
|
||
|
|
- [FileProperties.java](file://crm-file/src/main/java/com/crm/file/config/FileProperties.java)
|
||
|
|
- [SecurityUtils.java](file://crm-base/src/main/java/com/crm/base/security/SecurityUtils.java)
|
||
|
|
- [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java)
|
||
|
|
|
||
|
|
### 分片上传的并发控制、重试与异常恢复
|
||
|
|
- 并发控制:分片上传接口无状态,支持多实例并行上传;服务端以 uploadId+chunkIndex 唯一标识分片
|
||
|
|
- 重试机制:客户端对失败分片进行指数退避重试,服务端幂等处理重复分片
|
||
|
|
- 异常恢复:网络中断后重新发起分片上传,已完成分片无需重复上传;会话超时由清理任务回收
|
||
|
|
|
||
|
|
章节来源
|
||
|
|
- [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java)
|
||
|
|
- [OrphanChunkCleanupTask.java](file://crm-file/src/main/java/com/crm/file/task/OrphanChunkCleanupTask.java)
|
||
|
|
|
||
|
|
## 依赖关系分析
|
||
|
|
- FileController 依赖 FileApi(抽象),实际由 FileApiImpl 实现
|
||
|
|
- FileApiImpl 依赖 MinIO 存储与 FileInfoService 元数据服务
|
||
|
|
- FileInfoServiceImpl 依赖数据库 Mapper 进行持久化
|
||
|
|
- 统一响应与异常处理由 base 模块提供
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
graph LR
|
||
|
|
FC["FileController"] --> FA["FileApi"]
|
||
|
|
FA --> FAI["FileApiImpl"]
|
||
|
|
FAI --> MINIO["MinIO"]
|
||
|
|
FAI --> FS["FileInfoServiceImpl"]
|
||
|
|
FS --> DB["数据库"]
|
||
|
|
FC --> RESULT["Result/ResultCodeEnum"]
|
||
|
|
FC --> EXC["GlobalExceptionHandlerAdvice"]
|
||
|
|
```
|
||
|
|
|
||
|
|
图表来源
|
||
|
|
- [FileController.java](file://crm-file/src/main/java/com/crm/file/controller/FileController.java)
|
||
|
|
- [FileApi.java](file://crm-file/src/main/java/com/crm/file/api/FileApi.java)
|
||
|
|
- [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java)
|
||
|
|
- [FileInfoServiceImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileInfoServiceImpl.java)
|
||
|
|
- [Result.java](file://crm-base/src/main/java/com/crm/base/domain/result/Result.java)
|
||
|
|
- [ResultCodeEnum.java](file://crm-base/src/main/java/com/crm/base/domain/result/ResultCodeEnum.java)
|
||
|
|
- [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java)
|
||
|
|
|
||
|
|
章节来源
|
||
|
|
- [FileController.java](file://crm-file/src/main/java/com/crm/file/controller/FileController.java)
|
||
|
|
- [FileApi.java](file://crm-file/src/main/java/com/crm/file/api/FileApi.java)
|
||
|
|
- [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java)
|
||
|
|
- [FileInfoServiceImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileInfoServiceImpl.java)
|
||
|
|
- [Result.java](file://crm-base/src/main/java/com/crm/base/domain/result/Result.java)
|
||
|
|
- [ResultCodeEnum.java](file://crm-base/src/main/java/com/crm/base/domain/result/ResultCodeEnum.java)
|
||
|
|
- [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java)
|
||
|
|
|
||
|
|
## 性能考量
|
||
|
|
- 分片大小:合理设置分片大小(如 5MB~50MB)平衡网络开销与合并成本
|
||
|
|
- 并发度:客户端分片上传并发度建议 3~10,避免服务器资源耗尽
|
||
|
|
- 流式处理:下载使用流式 IO,避免大文件全量加载到内存
|
||
|
|
- 缓存策略:热点文件的 URL 或元数据可考虑短期缓存
|
||
|
|
- 存储优化:MinIO 桶分区与对象键前缀设计提升检索效率
|
||
|
|
|
||
|
|
[本节为通用指导,不直接分析具体文件]
|
||
|
|
|
||
|
|
## 故障排查指南
|
||
|
|
- 上传失败:检查文件大小与类型是否符合配置;查看全局异常处理器返回的错误码
|
||
|
|
- 分片丢失:确认客户端是否正确重试;检查会话是否被清理任务提前回收
|
||
|
|
- 下载失败:核对 fileId 是否存在;检查 MinIO 对象键与权限
|
||
|
|
- 进度不更新:确认分片上传接口是否成功返回;检查会话状态是否标记完成
|
||
|
|
|
||
|
|
章节来源
|
||
|
|
- [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java)
|
||
|
|
- [OrphanChunkCleanupTask.java](file://crm-file/src/main/java/com/crm/file/task/OrphanChunkCleanupTask.java)
|
||
|
|
- [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java)
|
||
|
|
|
||
|
|
## 结论
|
||
|
|
本文件上传下载模块通过分层架构与 MinIO 存储实现了高可靠、可扩展的单文件与分片上传能力,配合会话管理与定时清理保障断点续传与资源回收。统一响应与异常处理提升了可观测性与可维护性。建议在生产环境合理配置分片大小、并发度与超时策略,并结合监控告警保障稳定性。
|
||
|
|
|
||
|
|
[本节为总结,不直接分析具体文件]
|
||
|
|
|
||
|
|
## 附录:API 接口规范与示例
|
||
|
|
|
||
|
|
### 接口总览
|
||
|
|
- 单文件上传:POST /upload
|
||
|
|
- 分片初始化:POST /upload/init
|
||
|
|
- 分片上传:POST /upload/chunk
|
||
|
|
- 分片完成:POST /upload/complete
|
||
|
|
- 文件下载:GET /download
|
||
|
|
- 进度查询:GET /upload/status
|
||
|
|
|
||
|
|
### 请求与响应示例
|
||
|
|
- 单文件上传
|
||
|
|
- 请求:multipart/form-data,字段 file
|
||
|
|
- 响应:Result{code,msg,data:{fileId,url}}
|
||
|
|
- 分片初始化
|
||
|
|
- 请求:body 包含 fileName、fileSize、chunkSize
|
||
|
|
- 响应:Result{data:{sessionId,uploadId}}
|
||
|
|
- 分片上传
|
||
|
|
- 请求:multipart/form-data,字段 chunkIndex、chunkData
|
||
|
|
- 响应:Result{data:{uploaded:true}}
|
||
|
|
- 分片完成
|
||
|
|
- 请求:body 包含 uploadId、chunks[]
|
||
|
|
- 响应:Result{data:{fileId,url}}
|
||
|
|
- 文件下载
|
||
|
|
- 请求:query fileId
|
||
|
|
- 响应:二进制流,Content-Disposition 含文件名
|
||
|
|
- 进度查询
|
||
|
|
- 请求:query sessionId
|
||
|
|
- 响应:Result{data:{progress:百分比,uploadedChunks:数量}}
|
||
|
|
|
||
|
|
### 错误处理
|
||
|
|
- 统一错误码:ResultCodeEnum 定义业务错误码
|
||
|
|
- 全局异常:GlobalExceptionHandlerAdvice 捕获异常并返回标准错误格式
|
||
|
|
- 常见错误:文件过大、类型不支持、会话不存在、分片缺失、权限不足
|
||
|
|
|
||
|
|
章节来源
|
||
|
|
- [FileController.java](file://crm-file/src/main/java/com/crm/file/controller/FileController.java)
|
||
|
|
- [Result.java](file://crm-base/src/main/java/com/crm/base/domain/result/Result.java)
|
||
|
|
- [ResultCodeEnum.java](file://crm-base/src/main/java/com/crm/base/domain/result/ResultCodeEnum.java)
|
||
|
|
- [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java)
|
||
|
|
|
||
|
|
### 客户端集成建议与最佳实践
|
||
|
|
- 分片大小:默认 5MB~10MB,根据网络状况调整
|
||
|
|
- 并发控制:限制并发数为 3~10,避免阻塞线程池
|
||
|
|
- 重试策略:指数退避 + 最大重试次数,区分可重试与不可重试错误
|
||
|
|
- 进度反馈:轮询进度接口,展示上传进度条
|
||
|
|
- 安全性:校验文件类型与大小,服务端二次校验,避免越权访问
|
||
|
|
- 稳定性:断网恢复后从最后一个成功分片继续上传,避免重复传输
|
||
|
|
|
||
|
|
[本节为通用指导,不直接分析具体文件]
|