问题现状
在Java实现批量下载多文件(夹)压缩包(zip)篇幅中通过在服务器上创建临时文件,借助hutool
的ZipUtil
将文件(夹)压缩写入至response
的OutputStream
,实现了多文件(夹)的压缩包下载。其大致流程图可大致描述为:
经过分析和验证上述方式实现的批量下载存在着下列问题
- 1.文件非常大的情形下,步骤1.2. 4将文件先下载到服务器带来了额外的耗时操作,对于用户来说下载文件只需要将文件从文件系统直接写入响应即可。
- 2.由于请求类型为
POST
,所以浏览器不能自动下载文件,步骤5即使将流已写入响应,但是浏览器并不能打开下载页面,需要前端接收到所有Blob
才能打开下载,用户体验极差,易给用户造成批量下载没反应的错觉。
是否存在一种方案,可以将批量下载接口转为GET请求,且可以将文件(夹)直接写入到response的OutputStream?
解决思路
1.首先由于批量下载接口batchDownloadFile
的参数类型为List<DownloadFileParam>
为复杂参数,故无法直接将POST
请求修改为GET;这时候该怎么办呢?
架构思维中,比较常用的一种思路便是分层架构!我门可以将批量下载接口拆为两个接口
通过POST
方式保存下载参数List<DownloadFileParam>
到Redis
,并返回Redis
中该下载参数对应唯一标示key
的接口getBatchDownloadKey
如下
1 | java复制代码@PostMapping(value = "/getBatchDownloadKey") |
根据返回下载参数唯一标示Key
进行批量下载的GET
接口batchDownloadFile
接口,定义如下
1 | java复制代码 |
2.Java
提供了类ZipArchiveOutputStream
允许我们可以直接将带有目录结构的文件压缩到OutputStream
,其使用的伪代码如下
1 | java复制代码ZipArchiveOutputStream zous = new ZipArchiveOutputStream(response.getOutputStream()); |
这样我们就可以避免将文件下载到服务器带来的性能消耗。
3.整个过程的流程图如下
代码实现
保存下载参数请求getBatchDownloadKey
1 | java复制代码@PostMapping(value = "/getBatchDownloadKey") |
根据Key
下载文件的接口定义batchDownloadFile
1 | java复制代码@GetMapping(value = "/pass/batchDownloadFile", produces = "application/octet-stream;charset=UTF-8") |
fileService.batchDownloadFile
1 | java复制代码@Override |
downloadFileToServer
1 | java复制代码private void downloadFileToServer(String tmpDir, DownloadFileParam downloadFileParam, ZipArchiveOutputStream zous) throws Exception { |
方案总结
一般情况下下载接口最好用GET方式,浏览器会自动开始下载,除此之外,接口参数与下载接口参数间通过添加中间层解藕帮我们解决了POST下载转化为GET下载方式的问题,分层的架构思想是软件架构最常用的一种方式,再解决工作实际问题的过程中,我们要善于变通采用该方式。
本文转载自: 掘金