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.
30 KiB
30 KiB
文件API
**本文引用的文件** - [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) - [KkFileViewClient.java](file://crm-file/src/main/java/com/crm/file/service/KkFileViewClient.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) - [FileInfo.java](file://crm-file/src/main/java/com/crm/file/domain/entity/FileInfo.java) - [FileInfoMapper.java](file://crm-file/src/main/java/com/crm/file/mapper/FileInfoMapper.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) - [FileConstants.java](file://crm-file/src/main/java/com/crm/file/constant/FileConstants.java)目录
简介
本文件管理模块提供统一的文件上传、下载、预览、删除等能力,支持分片上传、断点续传与并发上传;集成 MinIO 对象存储与 KkFileView 在线预览服务;提供缩略图生成、临时访问链接、权限控制与批量操作。文档面向开发者与集成方,覆盖 HTTP 接口、数据模型、存储策略、安全校验、错误处理与优化建议。
项目结构
文件模块位于 crm-file 子模块,采用分层组织:
- controller:HTTP 接口层
- api:对外 API 抽象
- service:业务逻辑与外部服务客户端(MinIO、KkFileView)
- domain:实体、DTO、枚举与常量
- config:配置类(MinIO、调度任务、文件属性)
- task:定时清理任务(分片残留清理)
- mapper:数据库映射(文件元信息)
graph TB
subgraph "crm-file"
C["controller.FileController"] --> A["api.FileApi"]
A --> S1["service.impl.FileApiImpl"]
S1 --> S2["service.IFileInfoService"]
S2 --> S3["service.impl.FileInfoServiceImpl"]
S1 --> M["config.MinioConfig"]
S1 --> P["config.FileProperties"]
S1 --> K["service.KkFileViewClient"]
S3 --> E["domain.entity.FileInfo"]
S3 --> MAP["mapper.FileInfoMapper"]
T["task.OrphanChunkCleanupTask"] --> M
T --> S2
end
图表来源
- FileController.java
- FileApi.java
- FileApiImpl.java
- IFileInfoService.java
- FileInfoServiceImpl.java
- MinioConfig.java
- FileProperties.java
- KkFileViewClient.java
- FileInfo.java
- FileInfoMapper.java
- OrphanChunkCleanupTask.java
章节来源
- FileController.java
- FileApi.java
- FileApiImpl.java
- IFileInfoService.java
- FileInfoServiceImpl.java
- MinioConfig.java
- FileProperties.java
- KkFileViewClient.java
- FileInfo.java
- FileInfoMapper.java
- OrphanChunkCleanupTask.java
核心组件
- FileController:暴露 REST 接口,统一接收请求并委派给 FileApi。
- FileApi / FileApiImpl:定义并实现文件上传、下载、预览、删除、分片、续传、缩略图等核心流程。
- IFileInfoService / FileInfoServiceImpl:文件元数据持久化、查询、状态管理与事务边界。
- MinioConfig:MinIO 客户端配置与桶策略。
- FileProperties:文件大小限制、允许类型、路径规则等配置项。
- KkFileViewClient:调用第三方预览服务,生成预览链接或缩略图。
- OrphanChunkCleanupTask:定时清理未完成的分片文件,释放空间。
- FileInfo 实体与 Mapper:文件元信息表结构与数据访问。
章节来源
- FileController.java
- FileApi.java
- FileApiImpl.java
- IFileInfoService.java
- FileInfoServiceImpl.java
- MinioConfig.java
- FileProperties.java
- KkFileViewClient.java
- OrphanChunkCleanupTask.java
- FileInfo.java
- FileInfoMapper.java
架构总览
整体采用“控制器-服务-存储/外部服务”的分层架构:
- 控制器负责参数校验、鉴权与响应封装。
- 服务层编排上传、下载、预览、删除等业务流程,协调 MinIO 与 KkFileView。
- 配置层集中管理 MinIO、文件属性与调度任务。
- 数据层通过 MyBatis-Plus 维护文件元信息。
sequenceDiagram
participant Client as "客户端"
participant Controller as "FileController"
participant Api as "FileApiImpl"
participant MinIO as "MinIO 存储"
participant Preview as "KkFileView 预览服务"
participant DB as "数据库(FileInfo)"
Client->>Controller : "POST /api/file/upload/init"
Controller->>Api : "初始化分片会话"
Api->>DB : "创建上传会话/记录"
Api-->>Controller : "返回会话ID/分片大小"
Controller-->>Client : "会话信息"
loop "分片上传"
Client->>Controller : "POST /api/file/upload/chunk"
Controller->>Api : "上传分片"
Api->>MinIO : "PutObject(分片)"
Api->>DB : "记录分片状态"
Api-->>Controller : "分片上传结果"
Controller-->>Client : "分片成功/失败"
end
Client->>Controller : "POST /api/file/upload/complete"
Controller->>Api : "合并分片/完成上传"
Api->>MinIO : "CompleteMultipartUpload"
Api->>DB : "写入文件元信息"
Api-->>Controller : "文件信息"
Controller-->>Client : "文件URL/预览链接"
Client->>Controller : "GET /api/file/download/{id}"
Controller->>Api : "下载文件"
Api->>MinIO : "GetObject"
Api-->>Controller : "流式响应"
Controller-->>Client : "文件流"
Client->>Controller : "GET /api/file/preview/{id}"
Controller->>Api : "获取预览链接"
Api->>Preview : "生成预览URL"
Api-->>Controller : "预览URL"
Controller-->>Client : "预览地址"
图表来源
- FileController.java
- FileApiImpl.java
- MinioConfig.java
- KkFileViewClient.java
- FileInfoServiceImpl.java
- FileInfo.java
详细组件分析
文件上传接口(普通上传)
- 方法:POST
- 路径:/api/file/upload
- 请求体:multipart/form-data,字段 file(二进制文件)
- 响应:文件基本信息(ID、名称、大小、URL、预览链接)
- 校验:文件名白名单、大小限制、MIME 类型校验、重复检测
- 存储:MinIO 直传,按日期/用户维度组织桶路径
- 安全:鉴权拦截器校验登录态与权限
flowchart TD
Start(["进入上传接口"]) --> Validate["校验请求参数与权限"]
Validate --> CheckType{"文件类型允许?"}
CheckType --> |否| ErrType["返回类型不允许错误"]
CheckType --> |是| CheckSize{"文件大小合规?"}
CheckSize --> |否| ErrSize["返回大小超限错误"]
CheckSize --> |是| Upload["调用 MinIO 上传"]
Upload --> SaveMeta["持久化文件元信息"]
SaveMeta --> Return["返回文件信息"]
ErrType --> End(["结束"])
ErrSize --> End
Return --> End
图表来源
- FileController.java
- FileApiImpl.java
- FileProperties.java
- MinioConfig.java
- FileInfoServiceImpl.java
章节来源
- FileController.java
- FileApiImpl.java
- FileProperties.java
- MinioConfig.java
- FileInfoServiceImpl.java
分片上传(含断点续传与并发)
- 初始化会话:POST /api/file/upload/init
- 参数:fileName、fileSize、chunkSize、uploadId
- 响应:uploadId、分片大小、已存在分片列表
- 上传分片:POST /api/file/upload/chunk
- 参数:uploadId、chunkIndex、chunkData
- 行为:幂等上传,支持并发;记录分片状态
- 完成上传:POST /api/file/upload/complete
- 参数:uploadId、fileName、fileSize、checksum
- 行为:合并分片、落盘、写元信息、生成访问链接
- 断点续传:基于 uploadId 与分片索引去重,未上传分片可重试
- 并发上传:客户端并行上传分片,服务端保证幂等与顺序无关
sequenceDiagram
participant C as "客户端"
participant Ctrl as "FileController"
participant Api as "FileApiImpl"
participant MinIO as "MinIO"
participant DB as "FileInfoService"
C->>Ctrl : "init(uploadId, fileName, fileSize, chunkSize)"
Ctrl->>Api : "初始化会话"
Api->>DB : "创建会话/查询已上传分片"
Api-->>Ctrl : "返回分片策略"
Ctrl-->>C : "分片策略"
par "并发上传分片"
C->>Ctrl : "chunk(uploadId, index, data)"
Ctrl->>Api : "上传分片"
Api->>MinIO : "分片PutObject"
Api->>DB : "记录分片状态"
Api-->>Ctrl : "分片成功"
Ctrl-->>C : "分片成功"
end
C->>Ctrl : "complete(uploadId, checksum)"
Ctrl->>Api : "合并分片"
Api->>MinIO : "CompleteMultipartUpload"
Api->>DB : "写入文件元信息"
Api-->>Ctrl : "文件信息"
Ctrl-->>C : "文件URL/预览链接"
图表来源
- FileController.java
- FileApiImpl.java
- MultipartInitDTO.java
- UploadSession.java
- FileInfoServiceImpl.java
- MinioConfig.java
章节来源
- FileController.java
- FileApiImpl.java
- MultipartInitDTO.java
- UploadSession.java
- FileInfoServiceImpl.java
- MinioConfig.java
文件下载接口
- 方法:GET
- 路径:/api/file/download/{id}
- 参数:id(文件ID)、可选签名参数(如过期时间)
- 响应:文件流(Content-Disposition 设置下载名)
- 权限:需具备文件读取权限;支持私有桶访问(预签名 URL)
- 缓存:浏览器缓存控制头由服务端设置
sequenceDiagram
participant Client as "客户端"
participant Controller as "FileController"
participant Api as "FileApiImpl"
participant MinIO as "MinIO"
Client->>Controller : "GET /api/file/download/{id}"
Controller->>Api : "校验权限/构建下载参数"
Api->>MinIO : "GetObject(或预签名URL)"
MinIO-->>Api : "文件流/URL"
Api-->>Controller : "流/URL"
Controller-->>Client : "文件流/重定向"
图表来源
- FileController.java
- FileApiImpl.java
- MinioConfig.java
章节来源
- FileController.java
- FileApiImpl.java
- MinioConfig.java
文件预览接口
- 方法:GET
- 路径:/api/file/preview/{id}
- 功能:根据文件类型调用 KkFileView 生成预览链接或直接返回预览页面
- 参数:id(文件ID)、可选格式参数(pdf/html/img)
- 响应:预览页面或跳转链接
sequenceDiagram
participant Client as "客户端"
participant Controller as "FileController"
participant Api as "FileApiImpl"
participant Preview as "KkFileViewClient"
Client->>Controller : "GET /api/file/preview/{id}"
Controller->>Api : "解析文件类型/构造预览参数"
Api->>Preview : "生成预览URL"
Preview-->>Api : "预览URL"
Api-->>Controller : "预览URL"
Controller-->>Client : "跳转/嵌入预览"
图表来源
- FileController.java
- FileApiImpl.java
- KkFileViewClient.java
章节来源
- FileController.java
- FileApiImpl.java
- KkFileViewClient.java
文件删除接口
- 方法:DELETE
- 路径:/api/file/delete/{id}
- 权限:仅文件所有者或管理员可删除
- 行为:删除 MinIO 对象与数据库元信息;软删除标记可选
flowchart TD
Start(["进入删除接口"]) --> Auth["鉴权与所有权校验"]
Auth --> Exists{"文件存在?"}
Exists --> |否| NotFound["返回资源不存在"]
Exists --> |是| DeleteMinIO["删除 MinIO 对象"]
DeleteMinIO --> DeleteDB["删除/标记文件元信息"]
DeleteDB --> Ok["返回删除成功"]
NotFound --> End(["结束"])
Ok --> End
图表来源
- FileController.java
- FileApiImpl.java
- FileInfoServiceImpl.java
章节来源
- FileController.java
- FileApiImpl.java
- FileInfoServiceImpl.java
缩略图生成
- 触发时机:上传成功后异步生成缩略图(图片类型)
- 存储位置:MinIO 同桶下 thumbnail 目录
- 接口:GET /api/file/thumbnail/{id}
- 策略:若缩略图不存在则实时生成并缓存;支持尺寸参数
flowchart TD
Start(["缩略图请求"]) --> CheckCache["检查缩略图是否存在"]
CheckCache --> |存在| ReturnThumb["返回缩略图"]
CheckCache --> |不存在| GenThumb["生成缩略图"]
GenThumb --> SaveThumb["保存至 MinIO"]
SaveThumb --> ReturnThumb
图表来源
- FileApiImpl.java
- MinioConfig.java
章节来源
- FileApiImpl.java
- MinioConfig.java
批量操作接口
- 批量删除:POST /api/file/batch/delete
- 参数:ids(数组)
- 行为:逐个校验权限后执行删除
- 批量下载:POST /api/file/batch/download
- 参数:ids(数组)
- 行为:打包为 ZIP 流返回(大文件建议分页或异步任务)
sequenceDiagram
participant Client as "客户端"
participant Controller as "FileController"
participant Api as "FileApiImpl"
Client->>Controller : "POST /api/file/batch/delete {ids}"
Controller->>Api : "遍历校验与删除"
Api-->>Controller : "结果汇总"
Controller-->>Client : "批量结果"
图表来源
- FileController.java
- FileApiImpl.java
章节来源
- FileController.java
- FileApiImpl.java
临时链接生成
- 场景:私有桶访问、外链分享
- 接口:GET /api/file/presigned-url?fileId=xxx&expires=秒数
- 行为:生成 MinIO 预签名 URL,带过期时间与访问权限
- 安全:结合鉴权与访问控制策略
sequenceDiagram
participant Client as "客户端"
participant Controller as "FileController"
participant Api as "FileApiImpl"
participant MinIO as "MinIO"
Client->>Controller : "GET /api/file/presigned-url"
Controller->>Api : "校验权限/计算过期时间"
Api->>MinIO : "GeneratePresignedUrl"
MinIO-->>Api : "预签名URL"
Api-->>Controller : "URL"
Controller-->>Client : "临时链接"
图表来源
- FileController.java
- FileApiImpl.java
- MinioConfig.java
章节来源
- FileController.java
- FileApiImpl.java
- MinioConfig.java
分片残留清理任务
- 任务:定时扫描未完成上传的会话与分片,清理无效数据
- 策略:超过保留时间的会话自动清理,避免磁盘膨胀
- 配置:调度周期与保留时长在配置中管理
flowchart TD
Start(["定时任务启动"]) --> Scan["扫描未完成会话"]
Scan --> Filter{"是否超期?"}
Filter --> |否| Next["跳过"]
Filter --> |是| Cleanup["清理分片与会话"]
Cleanup --> Log["记录清理日志"]
Log --> End(["结束"])
Next --> End
图表来源
- OrphanChunkCleanupTask.java
- SchedulingConfig.java
章节来源
- OrphanChunkCleanupTask.java
- SchedulingConfig.java
依赖关系分析
- FileController 依赖 FileApi,解耦 HTTP 与业务逻辑。
- FileApiImpl 依赖 MinioConfig(MinIO 客户端)、FileProperties(配置)、KkFileViewClient(预览)。
- FileInfoServiceImpl 依赖 FileInfo 实体与 FileInfoMapper(MyBatis-Plus)。
- OrphanChunkCleanupTask 依赖 MinIO 与 FileInfoService 进行清理。
classDiagram
class FileController {
+upload()
+download()
+preview()
+delete()
+batchDelete()
+presignedUrl()
}
class FileApiImpl {
+initMultipart()
+uploadChunk()
+completeMultipart()
+download()
+preview()
+thumbnail()
+delete()
+presignedUrl()
}
class MinioConfig {
+client
+bucket
}
class FileProperties {
+maxFileSize
+allowedTypes
+pathRules
}
class KkFileViewClient {
+generatePreviewUrl()
}
class FileInfoServiceImpl {
+save()
+query()
+updateStatus()
}
class FileInfo {
+id
+name
+size
+url
+status
}
class FileInfoMapper
FileController --> FileApiImpl : "调用"
FileApiImpl --> MinioConfig : "使用"
FileApiImpl --> FileProperties : "读取配置"
FileApiImpl --> KkFileViewClient : "调用预览"
FileApiImpl --> FileInfoServiceImpl : "元数据操作"
FileInfoServiceImpl --> FileInfo : "实体"
FileInfoServiceImpl --> FileInfoMapper : "数据访问"
图表来源
- FileController.java
- FileApiImpl.java
- MinioConfig.java
- FileProperties.java
- KkFileViewClient.java
- FileInfoServiceImpl.java
- FileInfo.java
- FileInfoMapper.java
章节来源
- FileController.java
- FileApiImpl.java
- MinioConfig.java
- FileProperties.java
- KkFileViewClient.java
- FileInfoServiceImpl.java
- FileInfo.java
- FileInfoMapper.java
性能考虑
- 分片上传:合理设置分片大小(建议 5~10MB),提升大文件上传稳定性与并发度。
- 并发上传:客户端并行上传分片,服务端幂等处理,避免重复写入。
- 流式下载:使用流式响应减少内存占用,支持 Range 断点续传。
- 缩略图:异步生成与缓存,命中缓存直接返回。
- 预览服务:KkFileView 集群部署与缓存加速,避免单点瓶颈。
- 连接池:MinIO 客户端连接池与超时参数调优。
- 压缩与缓存:对静态资源启用 GZIP 与浏览器缓存。
- 限流与熔断:对上传/下载接口实施限流,异常时快速失败。
[本节为通用指导,不直接分析具体文件]
故障排查指南
- 上传失败:检查文件类型与大小限制、网络超时、MinIO 连通性。
- 分片丢失:核对 uploadId 与分片索引,查看分片状态记录。
- 预览失败:确认 KkFileView 服务可用性与文件格式支持。
- 下载慢:检查带宽、MinIO 延迟、是否命中预签名 URL。
- 权限问题:校验登录态、角色与数据范围。
- 清理任务:查看调度配置与日志,确认清理阈值合理。
章节来源
- FileApiImpl.java
- KkFileViewClient.java
- MinioConfig.java
- OrphanChunkCleanupTask.java
结论
文件模块以清晰的分层架构与完善的流程设计,提供了稳定高效的文件管理能力。通过分片上传、断点续传、并发上传与预览集成,满足企业级场景需求。配合 MinIO 与权限控制,确保数据安全与访问可控。建议在大规模使用时关注连接池、缓存与限流等性能优化点。
[本节为总结,不直接分析具体文件]
附录:接口清单与规范
接口清单
- 普通上传:POST /api/file/upload
- 分片初始化:POST /api/file/upload/init
- 分片上传:POST /api/file/upload/chunk
- 分片完成:POST /api/file/upload/complete
- 文件下载:GET /api/file/download/{id}
- 文件预览:GET /api/file/preview/{id}
- 缩略图:GET /api/file/thumbnail/{id}
- 删除文件:DELETE /api/file/delete/{id}
- 批量删除:POST /api/file/batch/delete
- 批量下载:POST /api/file/batch/download
- 临时链接:GET /api/file/presigned-url
请求参数与响应格式
- 上传参数:file(二进制)、fileName、fileSize、chunkSize、uploadId、chunkIndex、checksum
- 下载参数:id、可选签名参数
- 预览参数:id、format(可选)
- 删除参数:id、ids(批量)
- 响应格式:统一 Result 包装,包含 code、message、data
存储策略
- MinIO 桶命名:按业务域划分(如 file-prod、file-dev)
- 路径规则:/tenant/user/date/originalName
- 缩略图路径:/thumbnail/...
- 分片路径:/chunks/{uploadId}/...
支持的文件格式与大小限制
- 允许类型:image/、application/pdf、application/msword、application/vnd.openxmlformats-officedocument.、text/*
- 大小限制:默认 100MB,可通过配置调整
- 安全检查:MIME 类型校验、扩展名校验、内容扫描(可选)
安全校验规则
- 鉴权:JWT 登录态校验
- 权限:基于角色与数据范围的访问控制
- 输入校验:白名单类型、大小限制、文件名清洗
- 输出控制:下载与预览链接有效期控制
MinIO 存储配置
- 端点、AccessKey、SecretKey、Bucket、Region
- 连接池大小、超时时间、重试次数
- 桶策略:读写权限、匿名访问开关
文件访问权限控制
- 私有桶:通过预签名 URL 访问
- 公开桶:受限域名与 Referer 白名单
- 租户隔离:路径前缀区分租户
临时链接生成
- 过期时间:秒级精度,默认 1 小时
- 权限继承:继承原文件的访问策略
- 防滥用:频率限制与 IP 白名单
文件预览服务集成
- KkFileView 地址、超时、重试
- 支持的格式与渲染选项
- 缓存策略:本地缓存与 CDN 加速
错误处理机制
- 统一异常处理:BusinessErrorException、ResourceNotExistException
- 错误码:ResultCodeEnum 定义
- 重试策略:网络重试与指数退避
重试策略
- 上传分片:失败重试 3 次,间隔递增
- 下载:超时重试 1 次
- 预览:失败降级为原始文件下载
性能优化建议
- 分片大小与并发度调优
- 缩略图异步生成与缓存
- 预览服务集群与缓存
- 连接池与超时参数优化
- 限流与熔断保护
章节来源
- FileController.java
- FileApiImpl.java
- FileProperties.java
- MinioConfig.java
- KkFileViewClient.java
- FileInfoServiceImpl.java
- FileConstants.java