文件管理 v3.1.1+
这里讲的文件特指业务表单上传的附件,它们都保存在对象存储服务器上。为了减少冗余文件,我们需要记录每个文件的使用情况,这样才能定期清理掉未使用的文件。同时,将文件处理逻辑统一实现,可以精简业务代码,减少开发人员工作。
框架提供了标准功能,用来处理文件记录、文件绑定(标记使用)、文件查询等需求。
基本流程
为方便理解后续内容,我们先来看一下文件上传和处理的基本流程,确保大家处在同一认识基点。
上传
现在我们推荐使用前端直连对象存储服务(下文以 MinIO 代替)的形式上传文件,减少中转服务器和网络压力,尤其是上传文件体积较大的情况。
如上图所示,前端需要先请求预签名的 MinIO 上传地址,然后直接向 MinIO 服务上传文件。上传成功后,向后端请求创建文件记录。
提示
具体操作开发人员不必关心,由上传组件统一处理。调用接口分别为 /api/file-cloud-storage/sign/upload
、/api/file-cloud-storage/add
。
绑定
绑定即将文件标记为使用中状态,这时文件与特定的业务数据关联,成为与其相关的附件。
如上图所示,后端程序根据表单传入的必要信息进行文件绑定。
FileId
文件记录id,在上一步创建文件记录时返回。BusinessId
业务数据的唯一标识BusinessCode
由开发人员定义,用以表示表单内的上传来源。 想象一下,如果表单中有多个地方需要上传文件,那么在回显时就必须要知道文件应该显示在哪个位置。
图上还展示了一个未被使用的文件 0c952b
,未来可以根据这些记录统一清理掉 MinIO 上未使用的文件。
查询
在展示业务表单时,可以从文件管理服务获取关联的附件信息。这时仅需要传入 BusinessId
,一次性取得关联的所有附件。
特性标签
为方便使用,我们提供了基于特性(Attribute
)的文件绑定和文件查询实现。使用时将其添加到控制器方法
上即可。
BindBizFileAttribute
绑定文件。
参数
名称 | 类型 | 说明 |
---|---|---|
bizMode | BindFileBizMode | 业务操作模式,新增或编辑。 |
bizIdExpression | String | 业务 id 表达式,执行结果必须为 string。 |
filesExpression | String | 文件信息表达式,执行结果必须为 List<FileStorageBindDto>。 |
提示
bizMode
决定了从哪里获取业务 id。如果为新增模式,则从方法返回值中获取;反之则从方法入参中获取,同时还会尝试先解绑已关联的文件。
表达式执行的上下文对象为入参或返回值,分别挂载在 p 对象和 r 对象下。
注意
表达式严格区分大小写,更多信息请查看表达式引擎。
示例
下面给出一个使用示例。
[HttpPost]
[BindBizFile(BindFileBizMode.Create, "r.Body", "p.dto.Files")]
public Result<string> AddFoo(FooBizAddDto dto)
{
// 等同于 Result<string>.Success("001", "成功"),v3.0.0+ 可用。
return "001".ToResult();
}
[HttpPut]
[BindBizFile(BindFileBizMode.Edit, "p.dto.Id", "p.dto.Files")]
public Result EditFoo(FooBizAddDto dto)
{
return Result.Success();
}
public class FooBizAddDto : FileStorageBindBaseDto
{
public string Name { get; set; }
}
public class FooBizEditDto : FileStorageBindBaseDto
{
public string Id { get; set; }
public string Name { get; set; }
}
上例中,通过特性标签声明了将传入的文件信息绑定到业务id。
- 新增时,从方法返回值(框架定义为 r)的 Body 中获取业务id。
- 编辑时,从方法参数表(框架定义为 p)中的 dto 参数获取业务id。
同时,Dto 类从框架内置类 FileStorageBindBaseDto 继承了 Files 属性来接收传入的文件信息, 因此表达式为 p.dto.Files。 当然,也可以根据实际需要直接在 Dto 声明其它属性来接收文件信息,但类型必须为 List<FileStorageBindDto>。
前端数据格式
FileStorageBindDto 实际上规定了前端传入的数据格式,示例如下。
{
// 其它业务字段省略
files: [
{bizCode: 'foobiz-field1', fileIds: ['19203489231', '192049392018']},
{bizCode: 'foobiz-field2', fileIds: ['19203489231']}
]
}
ResponseBizFileAttribute
返回关联文件。方法返回值必须继承 FileStorageBaseVo。
参数
名称 | 类型 | 说明 |
---|---|---|
bizIdExpression | String | 业务id表达式,执行结果必须为 string。 |
注意
此处仅支持从返回结果中获取业务 id。
示例
下面是一个获取已绑定文件列表的示例。
[HttpGet]
[ResponseBizFile("r.Body.Id")]
public Result<FooBizVo> GetDetail()
{
FooBizVo foo = service.Get();
return foo.ToResult();
}
public class FooBizVo : FileStorageBaseVo
{
public string Id { get; set; }
public string Name { get; set; }
}
上例中,通过特性标签声明要将关联的文件信息添加到结果对象中。 此时仅需要指定业务 id,与之相关的所有文件都会被返回。
FooBizVo 类从 FileStorageBaseVo 继承了 BizFiles 属性,承载查询到的关联文件信息。
提示
查询文件信息时,会刷新文件访问地址的有效期。最长有效期为 1 天。
前端数据格式
为方便前端使用,文件数据按 BusinessCode 组织为对象形式。示例如下。
{
"code": 0,
"msg": "操作成功",
"body": {
// 其它业务字段省略
"bizFiles": {
"foobiz-field1": [
{
"id": "1088667670116564992",
"fileName": "test001.jpg",
"businessCode": "foobiz-field1",
"url": "http://foo.minio/static/00535a6618184740b4643fae65379016.jpg?signature="
},
{
"id": "1088667708173582336",
"fileName": "test002.jpg",
"businessCode": "foobiz-field1",
"url": "http://foo.minio/static/009a23236e914cb581ddae30c6e6f011.jpg?signature="
},
{
"id": "1088667754042490880",
"fileName": "test003.jpg",
"businessCode": "foobiz-field1",
"url": "http://foo.minio/static/0101334fdfd140fcae93ef7611e621a3.png?signature="
}
],
"foobiz-field2": [
{
"id": "1088667769743867904",
"fileName": "test004.jpg",
"businessCode": "foobiz-field2",
"url": "http://foo.minio/static/012c7c99c71f48b8b349edc0c55bef7c.jpg?signature="
}
]
}
}
}
服务调用
除了特性标签,也可以手动调用文件管理服务的绑定、删除、查询方法。具体请查看 FileStorageService 源码。
附录
FileStorageBindBaseDto
public class FileStorageBindBaseDto
{
public List<FileStorageBindDto> Files { get; set; }
}
FileStorageBindDto
public class FileStorageBindDto
{
public string BizCode { get; set; }
public List<string> FileIds { get; set; }
}
FileStorageBaseVo
public class FileStorageBaseVo
{
public Dictionary<string, List<FileStorageSimpleVo>> BizFiles { get; set; }
}
FileStorageSimpleVo
public class FileStorageSimpleVo
{
/// <summary>
/// 文件ID
/// </summary>
public string Id { get; set; }
/// <summary>
/// 原始文件名
/// </summary>
public string FileName { get; set; }
/// <summary>
/// 业务标识码
/// </summary>
public string BusinessCode { get; set; }
/// <summary>
/// 文件地址
/// </summary>
public string Url { get; set; }
}