springboot web 大表单多文件接口设计问题

300 天前
 9fan

springboot web 项目,现有一个要求,一个创建项目表单中,有十几个字段,其中有些是文件,而且不同文件之间是有不同的,意思是后端必须知道哪个对应哪个文件,业务要求,没办法,现在需要设计这个接口,麻烦问下,有什么好的解决方案。 方案一:使用 POST requestBody body 中让前端把文件作为 byte[]进行传递,应该是可以的

不知道大家有没有比较高效的方案

2286 次点击
所在节点    程序员
42 条回复
doublebu
300 天前
之前的项目是按 #7 老哥说的一样。
关于临时文件
1. 如果实现已经知道是临时文件,可以在保存到 S3 的时候给一个标记,比如都放到 /temp 文件夹中,定时调用 S3 的 API 删除文件夹就可以了
2. 可以开个定时任务,扫描数据库的文件字段,然后和 S3 文件列表做对比,找不到的就删掉,会麻烦一些
zpf124
300 天前
@limaofeng
@9fan

以这楼主这描述问题的能力想说服领导真的不太现实。
你要说服领导
1 、你要明白他为什么这么想
2 、你得有足够合理的方案能兼容他原有的想法,或者有足够的说服力劝他改变原想法。


至于上传文件必须有业务信息这部分有时候是合理的,比如我参与的有的系统涉及打包导出功能,所以资源文件的存放一开始就是和业务绑定的 比如 '/data/posts/{postid}/images/cover.jpg','/data/post/{postid}/attachments/a.zip' 因为要复制对应目录就可以导出所有有用资源,所以路径中拼接了 相关的业务 id , 因为需要业务 id 自然需要先创建了业务信息。

基于此,如果是我,我会提出这些解决方案,我个人倾向 2 > 1 > 3 > 4 。

1 、能不能先根据 id 生成策略创建一个 业务 id ,进入页面就返回一个 id 给前端, 然后上传文件 和提交业务信息分成两步来,都使用这个 id 。 这样的缺点就是会有冗余废数据,需要额外逻辑去判断和删除,而且原本应该是一个原子性的操作如今拆成几步了可能会有 bug 需要仔细 debug 。

2 、新写一个临时文件上传接口, 提交业务时创建信息,然后再从临时文件那复制文件到之前的上传接口就好,业务信息也有了, 临时文件目录只需要写个定时任务定期清理就好,甚至不清理也没问题,除了占空间和可能会被人当作分享图床外不会有任何副作用。 缺点除了这个临时目录也会冗余外,就是上传接口要调整一下或者新加一个支持从本地复制接口。

3 、一个接口支持多文件上传,写起来很简单,但文件如果大了,需要调整服务器允许上传文件上限,并且会严重占用带宽。

4 、将文件二进制 base64 发送, 除了个别接口只允许上传类似 logo 之类小文件的情况外,一遍不建议这么写。
limaofeng
300 天前
@9fan 文件上传接口要纯粹,就只上传单个文件,并返回 ID 。

所以你还是回到了 #7 的方案
如果你想清理过期文件。可以用一张表记录已经上传的文件: 比如 ID , 状态, 上传时间, 文件实际路径。

再业务表单里面。为文件进行一次确认操作(就是修改其状态)

然后用个定时任务,定期查询 文件记录表中的 状态。如果超过一定时间未处理的文件。 你就可以删除它。

这是你要的效果吗?
seedhk
300 天前
@9fan #20 这里有个问题就是万一表单提交成功了,临时文件丢了怎么办
limaofeng
300 天前
@seedhk 他描述的临时文件,应该不是存放在系统临时文件夹中的文件。不然就唧唧
zpf124
300 天前
@9fan

那就还是说单个请求太大的问题呗。

我个人方案是 上传服务增加临时目录,用对象存储的话搞个 temp 桶 或者 /temp 目录都可以, 然后写个定时任务,每隔几个小时清理掉临时目录下所有创建时间大于任务执行间隔的文件。
这个接口的所有文件都先上传到临时目录, 然后提交时后从临时目录复制一份到正确位置。

这样临时文件接口也不需要数据库记那些文件被使用了,那些是作废的。
9fan
300 天前
@seedhk 应该不可能,应该只有状态为已使用的才会被清理
@limaofeng 是的,有问题是,如果有多人在提交表单,怎么区分临时表中文件与表单的绑定关系的,如果按照 #20 所说中的第 1 方案让前端生成一个唯一表单 id 来与临时文件表中进行绑定,我觉得可行,但是怎么保证前端生成的一定是唯一的呢,如果交由后端生成,那什么时候该生成什么时候应该返回这个表单 id 呢。还有这个方案还是没有 @zpf124 的 2 方案好,简单好维护且高效,不知意下如何。其实 @zpf124 说的是的,他主要是考虑文件打包的功能,其实系统中文件如果这样设计,那么文件上传在微服务调用会区分多个接口调用,而且对应的下载接口数量也同等,前端已经在报怨了,说系统内文件接口太多,已经不知道调用哪个了,可能是接口设计抽象能力不够吧。还有另一个问题是,项目是部署在乙方自建服务器中的,有可能会有拦截,比如请求大小,文件的校验,这个也是未知的
9fan
300 天前
@zpf124 这个还是最好,谢谢了,下次一定描述尽量准确一点。不用记数据库,返回 url,前端就算离开这个表单,最终也是被延后几小时后删除,前端也能正确提交,唯一需要修改的是要不就在提交表单的业务接口去拉文件然后自己调用文件上传,因为是微服务,要么让其提供一个通知临时文件变永久文件的接口,文件 key 还是不变
limaofeng
300 天前
@9fan 无法在继续下去了。

"系统内文件接口太多" 我看到过很多系统,都只有一个文件上传接口(下载也只有一个)

"怎么区分临时表中文件与表单的绑定关系",为什么会有这个问题。业务表单 file1 = 后端上传文件后生成的 FileId 。 还需要如何区分。(如果你还是不懂,那会不会是自己太菜,或者单纯只是理解与表达有些障碍)

"还有另一个问题是,项目是部署在乙方自建服务器中的,有可能会有拦截,比如请求大小,文件的校验,这个也是未知的",这个是另一个问题,混在一起会成为解决问题的噪音。

如果你已经在维护一座屎山了,请不要尝试任何所谓的"高效的方案",抄袭前任的方案,多问前辈。别想搞个大新闻,不然你就会成为最大的新闻。
Belmode
300 天前
你领导也是真的奇葩。
如果知道字段名对应的文件类型,,,怎么不能区分业务呢?实在不行,加一个普通字段,用来区分业务也好。
9fan
300 天前
@limaofeng "怎么区分临时表中文件与表单的绑定关系",为什么会有这个问题。业务表单 file1 = 后端上传文件后生成的 FileId : 针对这个,我想的是多个表单怎么找到自己表单的临时文件 key ,不好意思是我想叉了,我当时想的记住这个表单,下次可以重用并且适时间内表单内文件是存在的,当前这个表单是知道的没问题,但是当他关闭这个表单后,又想重新提交的情况下,其实这种情况是不需要解决的,只需要定时清理无用的临时文件即可
9fan
300 天前
@Belmode 希望你不会不会遇到,算球,只是针对技术解决方案,不对领导与别人作出评价。
@limaofeng 还是应该学习这位老哥的 #13 心态。保命要紧。再贴一波:这有啥好纠结的,这么被动,领导设计,你无法撼动,而又没有能力说服领导采纳你的方案(前提你得有),那还有啥好商量的,领导咋说你咋干不就成了。不懂问领导,即使再沙壁的方案,也是正道
chendy
300 天前
问题不是很明确
但是吧,文件可以用参数名区分,一个参数多个文件可以拿到一个文件集合
而且既然 multipart 了,找个 part 塞个 json 也能传结构复杂的数据
所以有什么实现不了的呢…
levintrueno
300 天前
我这上传设计是一个单独接口,接收 MultipartFile 数组和一个枚举(区分业务),返回字符串 url 。然后把这个 url 放对应的字段就行。
tedzhou1221
300 天前
上传时,按业务类型,强行给文件名称后面追加业务类型??
例如 : 领导立项文件, 文件名为 xx.pdf , 把文件名改为 xx@@领导立项文件.pdf ,然后后端根据文件名切分
serical
300 天前
这种文件上传接口不都是单独的吗? 上传成功后返回文件唯一 ID, 再提交到后台啊
wellerman
300 天前
@9fan #2 后端统一成一个接口,前端选择后就上传。文件上传表里加状态做标记。最后全部提交成功, 文件状态由临时,变成成功,同时可以更新项目 ID 信息。最后状态是临时的,定期清掉。
koloonps
300 天前
@9fan 前端上传文件的时候修改 filename 为 uuid,后端去取数据的时候根据这个 uuid 去获取怎么样?
NewtonLeibniz
300 天前
上传前端做,后端接受参数就是上传后的地址
9fan
299 天前
@wellerman 这个也可以的,与增加临时上传接口本质差不多,你这个更加注重文件上传接口统一成一个的,对前端更加友好

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1022555

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX