在日常开发中,文件下载是一个常见的功能,虽然在项目中出现的频率可能不算太高,但几乎每个项目都会涉及。而有些下载需求相对复杂,虽然不是难点,但实现起来却十分繁琐。
因此,为了简化这一过程,有一个工具库,使得下载功能的实现变得更加简单快捷。
https://github.com/Linyuzai/concept/wiki/Concept-Download
一键下载任意对象
如果告诉你,现在仅需一个注解就能轻松下载任意对象,你会不会觉得很方便?
看起来似乎没有太大变化?那让我们看看一个实际场景。
真实业务中的应用
在一个设备管理平台中,每个设备都会有一个二维码图片,其地址存储在数据库的一个字段中。现需导出所有设备的二维码图片,并以设备名称命名,最终打包成 ZIP 文件。
实现这一需求,需要:
- 查询设备列表。
- 根据二维码 URL 下载图片并存入本地缓存。
- 处理缓存判断,避免重复下载。
- 并发下载以提升性能。
- 下载完成后生成 ZIP 文件。
- 将 ZIP 文件写入响应流。
整个实现过程大约需要 200 行代码,显得十分冗长繁琐。于是我思考是否有更简单的方法。
其实,我们只需要提供待下载的数据,比如文件路径、文件对象、文本内容、HTTP 地址,甚至是一个自定义对象,而无需关注下载逻辑。
于是,我们可以这样简化实现:
只需标注注解,系统会自动处理文件名称、下载内容、打包等逻辑,无需手动编写大量代码。
设计思路
这一功能的核心思想是基于 AOP 拦截下载请求,并结合 Spring WebFlux 进行异步处理。
@Download 注解说明
参数 | 说明 |
| 需要下载的内容,但是优先级低于返回值 如果方法返回值不为 |
| 如果为 |
| 指定下载时浏览器上显示的名称 如果不指定则会获取下载内容的名称,如文件则使用文件名 |
| 如果未指定,会尝试获取 如果尝试获取失败,则默认 |
| 压缩格式,默认 |
| 强制压缩 如果为 |
| 如果下载包含中文的文本文件出现乱码,可以尝试指定编码 |
| 统一的响应头,每2个为一组 |
| 额外的数据,当需要自行编写额外流程业务时可能会用到 |
整体流程
图片
响应式支持
为了兼容 Spring WebFlux,我们需要获取 ServerHttpResponse,但不能直接使用 RequestContextHolder,因此可以通过 WebFilter 进行注入:
然后在需要的地方通过 ReactiveDownloadHolder 获取响应对象。
处理下载任务
下载任务分为多个步骤,例如:
- 获取文件路径或 File 对象。
- 如果是多个文件,则先进行压缩处理。
- 将最终文件写入响应流。
因此,我们采用类似 Spring Cloud Gateway 过滤链的方式,设计了 DownloadHandler:
每个 DownloadHandler 处理特定任务,如下载、压缩、写入响应流等。
适配多种数据源
不同类型的下载对象需要不同的处理方式,例如文件、HTTP 地址、自定义对象等,因此我们抽象出 Source 接口,并通过 SourceFactory 进行匹配。
例如:
结语
这个工具库极大简化了文件下载功能,尤其是针对复杂的批量下载需求,只需简单的注解即可完成。如果你正在开发 SpringBoot 3.4 版本的项目,并需要实现高效的下载功能,不妨试试这个方案!