本文档基于以下代码整理:
src/main/java/com/ruoyi/basic/utils/FileUtil.javasrc/main/java/com/ruoyi/basic/enums/ApplicationTypeEnum.javasrc/main/java/com/ruoyi/basic/enums/RecordTypeEnum.javasrc/main/java/com/ruoyi/project/common/CommonController.javasrc/main/java/com/ruoyi/basic/controller/StorageAttachmentController.java用于说明本项目中文件上传、附件绑定、文件预览/下载的整体设计,以及 FileUtil 中每个方法的作用。
本项目的文件体系分成两层:
storage_blob:存文件实体信息uidFilenamepathbyteSizecontentTyperesourceKeystorage_attachment:存文件和业务记录的关联关系application:文件用途recordType:业务记录类型recordId:业务记录主键storageBlobId:关联的文件主表 id可以理解为:
storage_blob 负责“文件本身”storage_attachment 负责“文件挂在哪条业务数据上”接口:
POST /common/upload控制器位置:
src/main/java/com/ruoyi/project/common/CommonController.java入参:
filesList<MultipartFile>代码逻辑:
/common/uploadCommonController.upload() 调用 storageBlobService.upload(files, false)storage_blobStorageBlobVO 列表,里面通常会带:previewURLdownloadURL说明:
接口:
POST /common/public/upload代码逻辑:
CommonController.publicUpload() 调用 storageBlobService.upload(files, true)说明:
publicKey 参数,而不是临时 token上传完成后,如果需要把文件绑定到某条业务记录,需要再调用附件接口。
接口:
POST /storageAttachment/add控制器位置:
src/main/java/com/ruoyi/basic/controller/StorageAttachmentController.java核心请求对象:
StorageAttachmentDTO其中继承了 StorageAttachment,并额外包含:
storageBlobDTOs:待绑定的文件列表常用字段含义:
application:文件用途recordType:业务类型recordId:业务主键storageBlobDTOs[].id:上传成功后返回的文件 id示例请求体:
{
"application": "file",
"recordType": "common_file",
"recordId": 1001,
"storageBlobDTOs": [
{
"id": 12,
"application": "file"
},
{
"id": 13,
"application": "file"
}
]
}
绑定逻辑说明:
storage_blob.id/storageAttachment/addFileUtil 保存 storage_attachment接口:
GET /storageAttachment/list说明:
StorageAttachmentDTO 中的条件查询application、recordType、recordId接口:
DELETE /storageAttachment/delete请求体:
List<Long> ids说明:
ids 是附件关联表 id,一般是 storage_attachment.id接口:
GET /common/download/{fileName}支持两种访问方式:
tokenpublicKey代码逻辑:
publicKey,走 storageBlobService.getPublicFile(fileName, publicKey)storageBlobService.getFileByToken(fileName, token)fileUtil.compressFile(file) 做图片压缩处理接口:
GET /common/preview/{fileName}支持两种访问方式:
tokenpublicKey代码逻辑:
token 或 publicKeyfileUtil.compressFile(file)ApplicationTypeEnum位置:
src/main/java/com/ruoyi/basic/enums/ApplicationTypeEnum.java当前定义值:
| 枚举 | type | 说明 |
|---|---|---|
IMAGE |
image |
图片类文件 |
FILE |
file |
普通文件 |
AFTER_FILE |
after_file |
售后相关文件 |
BEFORE_FILE |
before_file |
售前/前置相关文件 |
APK |
apk |
安装包文件 |
作用:
FileUtil 的很多查询、删除、保存方法都会用到该字段RecordTypeEnum位置:
src/main/java/com/ruoyi/basic/enums/RecordTypeEnum.java作用:
recordType + recordId 和业务数据关联说明:
type 值common_fileafter_sales_servicequality_inspectproductnoticeFileUtil 方法说明FileUtil 是本套文件上传体系的核心工具类,主要负责:
下面按功能分组说明每个方法。
saveStorageAttachment(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId, List<StorageBlobDTO> storageBlobDTOS)作用:
逻辑:
application、recordType、recordIdstorageBlobDTOS 转成 storage_attachment 记录后批量插入适用场景:
saveStorageAttachmentByRecordTypeAndRecordId(String application, RecordTypeEnum recordType, Long recordId, List<StorageBlobDTO> storageBlobDTOS)作用:
recordType + recordId 保存附件关系,application 可指定,也可从每个文件对象里读取逻辑特点:
application == null,会根据 storageBlobDTO.application 分别删除旧关系application适用场景:
storage_blobdeleteStorageBlobs(List<Long> storageBlobIds)作用:
deleteStorageBlobsByStorageAttachmentIds(List<Long> storageAttachmentIds)作用:
storageBlobIddeleteStorageBlobsByApplicationAndRecordTypeAndRecordIds(ApplicationTypeEnum application, RecordTypeEnum recordType, List<Long> recordIds)作用:
适用场景:
deleteStorageBlobsByRecordTypeAndRecordId(RecordTypeEnum recordType, Long recordId)作用:
recordType + recordId 删除该业务记录下所有文件主表记录storage_attachmentdeleteStorageAttachmentsByStorageAttachmentIds(List<Long> storageAttachmentIds)作用:
deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId)作用:
特点:
deleteStorageAttachmentsByRecordTypeAndRecordId(RecordTypeEnum recordType, Long recordId)作用:
deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordIds(ApplicationTypeEnum application, RecordTypeEnum recordType, List<Long> recordIds)作用:
getStorageAttachmentsByStorageAttachmentIds(List<Long> storageAttachmentIds)作用:
storage_attachment 记录getStorageAttachmentsByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId)作用:
getStorageAttachmentsByRecordTypeAndRecordId(RecordTypeEnum recordType, Long recordId)作用:
StorageBlobVOgetStorageBlobVOsByApplicationAndRecordTypeAndRecordId(StorageAttachmentDTO storageAttachmentDTO)作用:
StorageAttachmentDTO 条件查询文件列表特点:
application 可选StorageBlobVOgetStorageBlobVOsByStorageAttachmentIds(List<Long> storageAttachmentIds)作用:
特点:
previewURLdownloadURLstorageAttachmentIdgetStorageBlobVOsByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId)作用:
getStorageBlobVOsByRecordTypeAndRecordId(RecordTypeEnum recordType, Long recordId)作用:
getStorageBlobVOsByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId, BigDecimal expired)作用:
说明:
expired 单位是分钟getStorageBlobVOsByStorageAttachmentIds(List<Long> storageAttachmentIds, BigDecimal expired)作用:
StorageAttachmentVOgetStorageAttachmentVOSByStorageAttachmentIds(List<Long> storageAttachmentIds)作用:
特点:
storageBlobVOSgetStorageAttachmentVOSByStorageAttachmentIds(List<Long> storageAttachmentIds, BigDecimal expired)作用:
getStorageAttachmentVOSByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId)作用:
getStorageAttachmentVOSByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId, BigDecimal expired)作用:
getFilePreviewURLByStorageAttachmentIds(List<Long> storageAttachmentIds)作用:
getFilePreviewURLByStorageAttachmentIds(List<Long> storageAttachmentIds, BigDecimal expired)作用:
getFilePreviewURLByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId)作用:
getFilePreviewURLByApplicationAndRecordTypeAndRecordIdAndExpired(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId, BigDecimal expired)作用:
getFileDownloadURLByStorageAttachmentIds(List<Long> storageAttachmentIds)作用:
getFileDownloadURLByStorageAttachmentIds(List<Long> storageAttachmentIds, BigDecimal expired)作用:
getFileDownloadURLByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId)作用:
getFileDownloadURLByApplicationAndRecordTypeAndRecordIdAndExpired(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId, BigDecimal expired)作用:
buildSignedPreviewUrl(StorageBlobVO storageBlob)作用:
实际调用:
buildSignedUrl(storageBlob, "/preview/", properties.getExpired())buildSignedDownloadUrl(StorageBlobVO storageBlob)作用:
实际调用:
buildSignedUrl(storageBlob, "/download/", properties.getExpired())buildSignedUrl(StorageBlobVO storageBlob, String actionPath, BigDecimal expired)作用:
支持:
actionPath = "/preview/"actionPath = "/download/"核心逻辑:
expired == -1,不生成 token,直接走 publicKey重要说明:
expired 单位为分钟cacheTokenUsage(String token, long expiredMillis)作用:
特点:
0说明:
buildSignedUrl() 内部调用buildTokenUsageKey(String token)作用:
格式:
file:token:usage:{token}说明:
validateTokenUsage(String token)作用:
核心逻辑:
说明:
resolveLimit()作用:
规则:
properties.getUseLimit() <= 0 时,默认返回 10说明:
buildRelativePath()作用:
格式:
yyyy/MMdd例如:
2026/0430用途:
compressFile(File file)作用:
压缩条件:
properties.getCompress()properties.getNeedCompressSize()处理逻辑:
thumb_原文件名Thumbnailator 按原尺寸压缩画质说明:
isImage(String fileName)作用:
支持后缀:
jpgjpegpng说明:
compressFile() 使用业务上最常见的接入顺序如下:
/common/upload/storageAttachment/addapplication + recordType + recordId + storageBlobDTOspreviewURL 或 downloadURL/common/upload 只负责文件入库/storageAttachment/add 才是和业务数据建立关系application 很重要recordId 下可能有多组不同用途附件applicationpublic/upload 上传的文件可走永久公开访问compressFile()本项目的文件上传方案是“两阶段模型”:
storage_blobstorage_attachment而 FileUtil 则负责把“上传后的文件”变成“可查询、可预览、可下载、可删除、可控时效”的完整附件能力。