上传下载
本篇介绍表单附件的上传下载。文件默认都保存在对象存储服务器上,为了减少冗余,我们需要记录每个文件的使用情况,这样才能定期清理掉未使用的文件。同时,将文件处理逻辑统一实现,可以精简业务代码,减少开发人员工作。
框架提供了标准功能,用来处理文件记录、文件绑定(标记使用)、文件查询等需求。
基本流程
为方便理解后续内容,我们先来看一下文件上传和处理的基本流程,确保大家处在同一认识基点。
上传
现在我们推荐使用前端直连对象存储服务(下文以 MinIO 代替)的形式上传文件,减少中转服务器和网络压力,尤其是上传文件体积较大的情况。
如上图所示,前端需要先请求预签名的 MinIO 上传地址,然后直接向 MinIO 服务上传文件。上传成功后,向后端请求创建文件记录。
提示
实际请求开发人员不必关心,由上传组件统一处理。调用接口分别为 /api/file-cloud-storage/sign/upload、/api/file-cloud-storage/add。
绑定
绑定即将文件标记为使用中状态,这时文件与特定的业务数据关联,成为与其相关的附件。
如上图所示,后端程序根据表单传入的必要信息进行文件绑定。
FileId文件记录id,在前一步上传文件后获得。BusinessId业务数据的唯一标识BusinessCode由开发人员定义,用以区分表单内的上传来源。 想象一下,如果表单中有多个地方需要上传文件,那么在回显时就必须要知道文件应该显示在哪个位置。
图上还展示了一个未被使用的文件 0c952b,未来可以根据这些记录统一清理掉 MinIO 上未使用的文件。
查询
在展示业务表单时,可以从文件管理服务获取关联的附件信息。这时需要传入 BusinessId,取得关联的所有附件。
注解
为方便使用,我们提供了声明式的文件绑定和文件查询实现。使用时将其添加到控制器或服务方法上即可。
@BoundFile
绑定文件。
参数
| 名称 | 类型 | 说明 |
|---|---|---|
| businessCode | String | 业务模块标识,用来区分一个表单多个上传组件的情况。 |
| businessId | String | 业务 id 表达式,执行结果必须为 String。 |
| ids | String | 文件 id 表达式,支持 String 和 List<String>。 |
提示
关于 businessId,如果为新增数据,则应该从方法返回值(声明为 result)中获取;编辑数据时则应该从方法入参中获取。
示例
下面给出一个使用示例。
@ApiOperation("添加")
@PostMapping
@BoundFile(businessCode = "'default'", businessId = "#result.body", ids = "#input.manual")
public AjaxResult add(@Valid @RequestBody FooBizAddDto input) {
String id = service.add(input);
return AjaxResult.success("成功", id);
}
@ApiOperation("修改")
@PutMapping
@BoundFile(businessCode = "'default'", businessId = "#input.id", ids = "#input.manual")
public AjaxResult edit(@Valid @RequestBody FooBizEditDto input) {
service.edit(input);
return AjaxResult.success();
}public class FooBizAddDto
{
private string manual;
// 省略其它属性和 get/set
}public class FooBizEditDto
{
private string id;
private string manual;
// 省略其它属性和 get/set
}上例中,通过注解声明了将传入的文件信息绑定到业务id。
- 新增时,从方法返回值(声明为 result)的 body 中获取业务id。
- 编辑时,从方法参数表中的 input 参数获取业务id。
@GetBoundFile
返回关联文件。
接口约定
业务关联的文件由框架自动写入返回数据,前提是实现特定的接口。
SingleGetBoundFileService 接口
- 实现 getBusinessId(),返回业务 id,以查询关联的文件。
- 实现 getBusinessCode(), 返回业务模块名,区分多个上传组件。
- 实现 setBoundFiles(List<FileCloudStorageSimpleVo> vos),接收传入的文件信息。
MultiGetBoundFileService 接口
- 实现 getBusinessId(),返回业务 id,以查询关联的文件。
- 实现 setBoundFilesByMap(Map<String, List<FileCloudStorageSimpleVo>> voMap),接收传入的文件信息。Map 的键为 BusinessCode。
示例
下面是一个获取已绑定文件列表的示例。
@GetMapping("/{id}")
@GetBoundFile
public AjaxResult<FooBizVo> detail(@PathVariable String id) {
FooBizVo vo = service.getById(id);
return AjaxResult.success(vo);
}public class FooBizVo implements MultiGetBoundFileService
{
private String id;
private Map<String, List<FileCloudStorageSimpleVo>> manualFiles = Collections.emptyMap();
@Override
public String getBusinessId() {
return id;
}
@Override
public void setBoundFilesByMap(Map<String, List<FileCloudStorageSimpleVo>> voMap) {
this.manualFiles = voMap;
}
}上例中,通过注解声明要将关联的文件信息添加到结果对象中,关键在于 Vo 类对接口的实现。
提示
查询文件信息时,会刷新文件访问地址的有效期。最长有效期为 1 天。