自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

太方便了!SpringBoot 只需一個(gè)注解,就能搞定任意對(duì)象下載!

開(kāi)發(fā) 前端
?在日常開(kāi)發(fā)中,文件下載是一個(gè)常見(jiàn)的功能,雖然在項(xiàng)目中出現(xiàn)的頻率可能不算太高,但幾乎每個(gè)項(xiàng)目都會(huì)涉及。而有些下載需求相對(duì)復(fù)雜,雖然不是難點(diǎn),但實(shí)現(xiàn)起來(lái)卻十分繁瑣。

在日常開(kāi)發(fā)中,文件下載是一個(gè)常見(jiàn)的功能,雖然在項(xiàng)目中出現(xiàn)的頻率可能不算太高,但幾乎每個(gè)項(xiàng)目都會(huì)涉及。而有些下載需求相對(duì)復(fù)雜,雖然不是難點(diǎn),但實(shí)現(xiàn)起來(lái)卻十分繁瑣。

因此,為了簡(jiǎn)化這一過(guò)程,有一個(gè)工具庫(kù),使得下載功能的實(shí)現(xiàn)變得更加簡(jiǎn)單快捷。

https://github.com/Linyuzai/concept/wiki/Concept-Download

一鍵下載任意對(duì)象

如果告訴你,現(xiàn)在僅需一個(gè)注解就能輕松下載任意對(duì)象,你會(huì)不會(huì)覺(jué)得很方便?

import com.icoderoad.download.annotation.Download;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;


@RestController
public class DownloadController {


    @Download(source = "classpath:/download/README.txt")
    @GetMapping("/classpath")
    public void downloadFromClasspath() {
    }


    @Download
    @GetMapping("/file")
    public File downloadFile() {
        return new File("/Users/Shared/README.txt");
    }


    @Download
    @GetMapping("/http")
    public String downloadFromHttp() {
        return "http://127.0.0.1:8080/icoderoad-download/image.jpg";
    }
}

看起來(lái)似乎沒(méi)有太大變化?那讓我們看看一個(gè)實(shí)際場(chǎng)景。

真實(shí)業(yè)務(wù)中的應(yīng)用

在一個(gè)設(shè)備管理平臺(tái)中,每個(gè)設(shè)備都會(huì)有一個(gè)二維碼圖片,其地址存儲(chǔ)在數(shù)據(jù)庫(kù)的一個(gè)字段中?,F(xiàn)需導(dǎo)出所有設(shè)備的二維碼圖片,并以設(shè)備名稱(chēng)命名,最終打包成 ZIP 文件。

實(shí)現(xiàn)這一需求,需要:

  1. 查詢?cè)O(shè)備列表。
  2. 根據(jù)二維碼 URL 下載圖片并存入本地緩存。
  3. 處理緩存判斷,避免重復(fù)下載。
  4. 并發(fā)下載以提升性能。
  5. 下載完成后生成 ZIP 文件。
  6. 將 ZIP 文件寫(xiě)入響應(yīng)流。

整個(gè)實(shí)現(xiàn)過(guò)程大約需要 200 行代碼,顯得十分冗長(zhǎng)繁瑣。于是我思考是否有更簡(jiǎn)單的方法。

其實(shí),我們只需要提供待下載的數(shù)據(jù),比如文件路徑、文件對(duì)象、文本內(nèi)容、HTTP 地址,甚至是一個(gè)自定義對(duì)象,而無(wú)需關(guān)注下載邏輯。

于是,我們可以這樣簡(jiǎn)化實(shí)現(xiàn):

import com.icoderoad.download.annotation.Download;
import com.icoderoad.download.annotation.SourceName;
import com.icoderoad.download.annotation.SourceObject;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;


@RestController
public class DeviceDownloadController {


    private final DeviceService deviceService;


    public DeviceDownloadController(DeviceService deviceService) {
        this.deviceService = deviceService;
    }


    @Download(filename = "二維碼.zip")
    @GetMapping("/download")
    public List<Device> downloadDevices() {
        return deviceService.all();
    }
}


class Device {
    private String name;


    @SourceObject
    private String qrCodeUrl;


    @SourceName
    public String getQrCodeName() {
        return name + ".png";
    }
}

只需標(biāo)注注解,系統(tǒng)會(huì)自動(dòng)處理文件名稱(chēng)、下載內(nèi)容、打包等邏輯,無(wú)需手動(dòng)編寫(xiě)大量代碼。

設(shè)計(jì)思路

這一功能的核心思想是基于 AOP 攔截下載請(qǐng)求,并結(jié)合 Spring WebFlux 進(jìn)行異步處理。

@Download 注解說(shuō)明

參數(shù)

說(shuō)明

source

需要下載的內(nèi)容,但是優(yōu)先級(jí)低于返回值 如果方法返回值不為null則會(huì)使用返回值作為下載的內(nèi)容

inline

如果為true,可以直接在瀏覽器預(yù)覽 需要配合contentType,如圖片或視頻,默認(rèn)false 視頻文件目前存在一些問(wèn)題,還在測(cè)試階段

filename

指定下載時(shí)瀏覽器上顯示的名稱(chēng) 如果不指定則會(huì)獲取下載內(nèi)容的名稱(chēng),如文件則使用文件名

contentType

如果未指定,會(huì)嘗試獲取 如果嘗試獲取失敗,則默認(rèn)application/octet-stream 或application/x-zip-compressed

compressFormat

壓縮格式,默認(rèn)zip

forceCompress

強(qiáng)制壓縮 如果為true,不管下載的文件有幾個(gè)都會(huì)壓縮 如果為false,有多個(gè)文件時(shí)壓縮,只有一個(gè)文件時(shí)不壓縮 默認(rèn)false

charset

如果下載包含中文的文本文件出現(xiàn)亂碼,可以嘗試指定編碼

headers

統(tǒng)一的響應(yīng)頭,每2個(gè)為一組

extra

額外的數(shù)據(jù),當(dāng)需要自行編寫(xiě)額外流程業(yè)務(wù)時(shí)可能會(huì)用到

整體流程

圖片圖片

響應(yīng)式支持

為了兼容 Spring WebFlux,我們需要獲取 ServerHttpResponse,但不能直接使用 RequestContextHolder,因此可以通過(guò) WebFilter 進(jìn)行注入:

import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;


public class ReactiveDownloadFilter implements WebFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        return chain.filter(exchange)
                .contextWrite(ctx -> ctx.put(ServerHttpResponse.class, exchange.getResponse()));
    }
}

然后在需要的地方通過(guò) ReactiveDownloadHolder 獲取響應(yīng)對(duì)象。

import org.springframework.web.server.ServerHttpResponse;
import reactor.core.publisher.Mono;


public class ReactiveDownloadHolder {
    public static Mono<ServerHttpResponse> getResponse() {
        return Mono.deferContextual(ctx -> Mono.just(ctx.get(ServerHttpResponse.class)));
    }
}

處理下載任務(wù)

下載任務(wù)分為多個(gè)步驟,例如:

  1. 獲取文件路徑或 File 對(duì)象。
  2. 如果是多個(gè)文件,則先進(jìn)行壓縮處理。
  3. 將最終文件寫(xiě)入響應(yīng)流。

因此,我們采用類(lèi)似 Spring Cloud Gateway 過(guò)濾鏈的方式,設(shè)計(jì)了 DownloadHandler:

import reactor.core.publisher.Mono;

public interface DownloadHandler {
    Mono<Void> handle(DownloadContext context, DownloadHandlerChain chain);
}

每個(gè) DownloadHandler 處理特定任務(wù),如下載、壓縮、寫(xiě)入響應(yīng)流等。

適配多種數(shù)據(jù)源

不同類(lèi)型的下載對(duì)象需要不同的處理方式,例如文件、HTTP 地址、自定義對(duì)象等,因此我們抽象出 Source 接口,并通過(guò) SourceFactory 進(jìn)行匹配。

public interface SourceFactory {
    boolean support(Object source, DownloadContext context);
    Source create(Object source, DownloadContext context);
}

例如:

public class FileSourceFactory implements SourceFactory {
    @Override
    public boolean support(Object source, DownloadContext context) {
        return source instanceof File;
    }


    @Override
    public Source create(Object source, DownloadContext context) {
        return new FileSource((File) source);
    }
}

結(jié)語(yǔ)

這個(gè)工具庫(kù)極大簡(jiǎn)化了文件下載功能,尤其是針對(duì)復(fù)雜的批量下載需求,只需簡(jiǎn)單的注解即可完成。如果你正在開(kāi)發(fā) SpringBoot 3.4 版本的項(xiàng)目,并需要實(shí)現(xiàn)高效的下載功能,不妨試試這個(gè)方案!

責(zé)任編輯:武曉燕 來(lái)源: 路條編程
相關(guān)推薦

2022-09-14 10:16:12

MyBatis加密解密

2024-10-17 11:09:46

2024-09-27 15:24:15

Spring數(shù)據(jù)加解密

2022-05-26 10:42:30

數(shù)據(jù)權(quán)限注解

2022-06-14 10:47:27

項(xiàng)目日志PUT

2022-07-15 14:26:36

開(kāi)源工具IP

2021-10-19 18:22:50

Map 注冊(cè)表源碼

2022-06-27 08:36:27

分布式事務(wù)XA規(guī)范

2021-09-24 15:00:26

微信PC電腦移動(dòng)應(yīng)用

2021-11-23 23:01:40

Windows微軟系統(tǒng)

2024-02-19 00:21:45

開(kāi)源圖片

2021-09-24 09:59:59

復(fù)制粘貼PythonPDF

2019-07-24 10:50:56

Python 開(kāi)發(fā)編程語(yǔ)言

2021-02-08 11:46:17

Python自動(dòng)化郵件

2020-01-07 11:30:50

圖像識(shí)別AI人工智能

2024-04-15 00:00:02

OpenAI模型性能

2021-10-22 22:38:01

手機(jī)系統(tǒng)技術(shù)

2021-10-25 22:50:04

手機(jī)系統(tǒng)設(shè)置

2025-04-08 01:00:00

Spring開(kāi)發(fā)系統(tǒng)

2023-11-27 07:33:55

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)