作者:微信小助手
发布时间:2024-03-19T12:02:47
目录 文章来源:https://blog.csdn.net/m0_64360721/article/details/122960311 介绍 下载功能应该是比较常见的功能了,虽然一个项目里面可能出现的不多,但是基本上每个项目都会有,而且有些下载功能其实还是比较繁杂的,倒不是难,而是麻烦。 所以结合之前的下载需求,我写了一个库来简化下载功能的实现 ❝ 传送门:https://github.com/Linyuzai/concept/wiki/Concept-Download ❞ 如果我说现在只需要一个注解就能帮你下载任意的对象,是不是觉得非常的方便 感觉差别不大?那就听听我遇到的一个下载需求 我们有一个平台是管理设备的,然后每个设备都会有一个二维码图片,用一个字段存储的 http 地址 现在需要导出所有设备二维码图片的压缩包,图片名称需要用设备名称加 .png 后缀,需求上来说并不难,但是着实有点麻烦 看着我实现了将近 200 行的代码,真是又臭又长,一个下载功能咋能那么麻烦呢,于是我就想有没有更简单的方式 我当时的需求很简单,我想着我只要提供需要下载的数据,比如一个文件路径,一个文件对象,一段字符串文本,一个http地址,或者混搭了前面所有类型的一个集合,甚至是我们自定义的某个类的实例,后面的事情我就不用管了 文件路径是一个文件还是一个目录?字符串文本需要先写入一个文本文件中?http资源如何下载到本地?多个文件怎么压缩?最后怎么写到响应中?我才不想花时间管这些 比如就像我现在这个需求,我只要返回设备列表就行了,其他的事情我都不用管 通过在 Device 的字段上标注某些注解(或是实现某个接口)来指定文件名称和文件地址 如果能这样实现,省时省心省力,又多了写 199 行代码的摸鱼时间难道不香么 思路 下面来讲讲这个库的主要设计思路,以及中间遇到的坑,大家有兴趣可以继续往下看 其实基于一开始的设想,我觉得功能并没有多复杂,于是就决定开肝 只是万万没想到实现起来比我想象的更复杂(这是后话了) 首先整个库基于响应式编程,但却并不是完全意义上的响应式,只能说是 为什么会这样呢,很大的一个原因是由于需要兼容webmvc和webflux,导致我仅仅是将之前实现的InputStream方式重构成了响应式,所以就出现了这样的组合 这也是我遇到的最大的一个坑,我先前已经基本调通了基于Servlet的整个下载流程,然后就想着支持一下webflux 大家都知道webmvc中,我们可以通过RequestContextHolder来获得请求和响应对象,但是在webflux中就不行了,当然我们可以在方法参数中注入 结合Spring自带的注入功能,我们就可以通过AOP拿到响应的入参了,但是总觉得这样写有点多余,强迫症表示不能忍 有什么办法既能把用不到的入参干掉,又能拿到响应对象呢,在网上找到了一种实现方式
@Download(source = "classpath:/download/README.txt")
@GetMapping("/classpath")
public void classpath() {
}
@Download
@GetMapping("/file")
public File file() {
return new File("/Users/Shared/README.txt");
}
@Download
@GetMapping("/http")
public String http() {
return "http://127.0.0.1:8080/concept-download/image.jpg";
}
@Download(filename = "二维码.zip")
@GetMapping("/download")
public List<Device> download() {
return deviceService.all();
}
public class Device {
//设备名称
private String name;
//设备二维码
//注解表示该http地址是需要下载的数据
@SourceObject
private String qrCodeUrl;
//注解表示文件名称
@SourceName
public String getQrCodeName() {
return name + ".png";
}
//省略其他属性方法
}
基础
Mono<InputStream
>这样的。。。奇怪组合?@Download(source = "classpath:/download/README.txt")
@GetMapping("/classpath")
public void classpath(ServerHttpResponse response) {
}