Springboot 一行程式碼實現檔案上傳 20個平臺!少寫程式碼到極致

2022-10-25 12:01:29

大家好,我是小富~

又是做好人好事的一天,有個小可愛私下問我有沒有好用的springboot檔案上傳工具,這不巧了嘛,正好我私藏了一個好東西,順便給小夥伴們也分享一下,demo地址放在文末了。

檔案上傳在平常不過的一個功能,做後端開發的基本都會接觸到,雖然不難可著實有點繁瑣。資料流的開閉、讀取還容易出錯,尤其是在對接一些OSS物件儲存平臺,一個平臺一堆SDK程式碼看起來亂糟糟的。

下邊給我大家推薦一個工具Spring File Storage,上傳檔案只要些許設定一行程式碼搞定,開發效率槓槓的,一起看看是不是有這麼流批!

官網:https://spring-file-storage.xuyanwu.cn

Spring File Storage工具幾乎整合了市面上所有的OSS物件儲存平臺,包括本地FTPSFTPWebDAV阿里雲OSS華為雲OBS七牛雲Kodo騰訊雲COS百度雲 BOS又拍雲USSMinIO京東雲 OSS網易數帆 NOS等其它相容 S3 協定的平臺,只要在springboot中通過極簡的方式就可以實現檔案儲存。

簡單設定

下邊以本地和Aliyun OSS上傳為例,pom.xml中引入必要的spring-file-storage.jar注意: 如果要上傳檔案到OSS平臺,需要引入對應平臺的SDK包。

<!-- spring-file-storage 必須要引入 -->
<dependency>
    <groupId>cn.xuyanwu</groupId>
    <artifactId>spring-file-storage</artifactId>
    <version>0.5.0</version>
</dependency>

<!-- 阿里雲oss -->
<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.10.2</version>
</dependency>

application.yml檔案中設定些基礎資訊。

  • enable-storage:只有狀態開啟才會被識別到
  • default-platform:預設的上傳平臺
  • domain:生成的檔案url中存取的域名
  • base-path:儲存地址
  • thumbnail-suffix:縮圖字尾

要是上傳OSS物件儲存平臺,將aliyun oss提供的變數設定到相應的模組上即可。

spring:
  #檔案儲存設定(本地、oss)
  file-storage:
    default-platform: local-1
    thumbnail-suffix: ".min.jpg" #縮圖字尾
    local:
      - platform: local-1 # 儲存平臺標識
        enable-storage: true #是否開啟本儲存(只能選一種)
        enable-access: true #啟用存取(線上請使用 Nginx 設定,效率更高)
        domain: "http://127.0.0.1:2222" #存取域名,注意後面要和path-patterns保持一致,「/」結尾
        base-path: /tmp/Pictures/ # 儲存地址
        path-patterns: /** #存取路徑
    aliyun-oss:
      - platform: aliyun-oss
        enable-storage: true
        access-key: xxxx
        secret-key: xxxx
        end-point: xxx
        bucket-name: firebook
        domain: http://fire100.top
        base-path: #雲平臺檔案路徑

springboot啟動類中增加註解@EnableFileStorage,顯式的開啟檔案上傳功能,到這就可以用了

@EnableFileStorage // 檔案上傳工具
@SpringBootApplication
public class SpringbootFileStorageApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootFileStorageApplication.class, args);
    }
}

上傳檔案

接下來在業務類中引入FileStorageService服務,如下只要一行程式碼就可以完成檔案上傳,是不是So easy,下載也是如法炮製。

@RestController
public class FileController {

    @Autowired
    private FileStorageService fileStorageService;

    /**
     * 公眾號:程式設計師小富
     * 上傳檔案
     */
    @PostMapping(value = {"/upload"})
    public Object upload(MultipartFile file) {
        FileInfo upload  = fileStorageService.of(file).upload();
        return upload;
    }
}

我們用postman測試上傳一張圖片,看到圖片已經成功傳到了/tmp/Pictures目錄下,返回結果中包含了完整的存取檔案的URL路徑。

不僅如此spring-file-storage還支援多種檔案形式,URIURLStringbyte[]InputStreamMultipartFile,使開發更加靈活。

檔案上傳功能,更多時候我們都是在上傳圖片,那就會有動態裁剪圖片生成縮圖的需求,這些 spring-file-storage 都可以很容易實現。

/**
 * 公眾號:程式設計師小富
 * 上傳圖片裁剪大小並生成一張縮圖
 */
@PostMapping("/uploadThumbnail")
public FileInfo uploadThumbnail(MultipartFile file) {
    return fileStorageService.of(file)
            .image(img -> img.size(1000,1000))  //將圖片大小調整到 1000*1000
            .thumbnail(th -> th.size(200,200))  //再生成一張 200*200 的縮圖
            .upload();
}

而且我們還可以動態選擇上傳平臺,組態檔中將所有平臺開啟,在實際使用中自由的選擇。

/**
 * 公眾號:程式設計師小富
 * 上傳檔案到指定儲存平臺,成功返回檔案資訊
 */
@PostMapping("/upload-platform")
public FileInfo uploadPlatform(MultipartFile file) {
    return fileStorageService.of(file)
            .setPlatform("aliyun-oss")    //使用指定的儲存平臺
            .upload();
}

下載檔案

下載檔案也同樣的簡單,可以直接根據檔案url或者檔案流下載。

/**
 * 公眾號:程式設計師小富
 * 下載檔案
 */
@PostMapping("/download")
public void download(MultipartFile file) {
    // 獲取檔案資訊
    FileInfo fileInfo = fileStorageService.getFileInfoByUrl("http://file.abc.com/test/a.jpg");
    
    // 下載到檔案
    fileStorageService.download(fileInfo).file("C:\\a.jpg");

    // 直接通過檔案資訊中的 url 下載,省去手動查詢檔案資訊記錄的過程
    fileStorageService.download("http://file.abc.com/test/a.jpg").file("C:\\a.jpg");

    // 下載縮圖
    fileStorageService.downloadTh(fileInfo).file("C:\\th.jpg");
}

提供了監聽下載進度的功能,可以清晰明瞭的掌握檔案的下載情況。

// 下載檔案 顯示進度
fileStorageService.download(fileInfo).setProgressMonitor(new ProgressListener() {
    @Override
    public void start() {
        System.out.println("下載開始");
    }

    @Override
    public void progress(long progressSize,long allSize) {
        System.out.println("已下載 " + progressSize + " 總大小" + allSize);
    }

    @Override
    public void finish() {
        System.out.println("下載結束");
    }
}).file("C:\\a.jpg");

檔案存在、刪除

我們還可以根據檔案的URL地址來判斷檔案是否存在、以及刪除檔案。

//直接通過檔案資訊中的 url 刪除,省去手動查詢檔案資訊記錄的過程
fileStorageService.delete("http://file.abc.com/test/a.jpg");
//直接通過檔案資訊中的 url 判斷檔案是否存在,省去手動查詢檔案資訊記錄的過程
boolean exists2 = fileStorageService.exists("http://file.abc.com/test/a.jpg");

切面

工具還提供了每種操作的切面,可以在每個動作的前後進行干預,比如打紀錄檔或者玩點花活,實現FileStorageAspect類重寫對應動作的xxxAround方法。

**
 * 使用切面列印檔案上傳和刪除的紀錄檔
 */
@Slf4j
@Component
public class LogFileStorageAspect implements FileStorageAspect {

    /**
     * 上傳,成功返回檔案資訊,失敗返回 null
     */
    @Override
    public FileInfo uploadAround(UploadAspectChain chain, FileInfo fileInfo, UploadPretreatment pre, FileStorage fileStorage, FileRecorder fileRecorder) {
        log.info("上傳檔案 before -> {}",fileInfo);
        fileInfo = chain.next(fileInfo,pre,fileStorage,fileRecorder);
        log.info("上傳檔案 after -> {}",fileInfo);
        return fileInfo;
    }
}

demo案例地址:https://github.com/chengxy-nds/Springboot-Notebook/tree/master/springboot-file-storage

總結

用了這個工具確實極大的減少了上傳檔案所帶來的程式碼量,提升了開發效率,使用過程中暫未發現有什麼坑,好東西就是要大家分享,如果符合你的需求,猶豫什麼用起來吧。

技術交流,公眾號:程式設計師小富