Class ZipFileResponseBuilder

java.lang.Object
io.leandev.appfuse.file.ZipFileResponseBuilder

public class ZipFileResponseBuilder extends Object

ZIP 檔案下載 Response 建構器(支援 Range Request)

先產生 ZIP 暫存檔,再提供下載。適用於:

  • 大型 ZIP 檔案需要斷點續傳
  • 需要支援 Range Request 的場景

運作方式:

  • 建立暫存 ZIP 檔案
  • 使用 RangeUtils.evaluate(String, long) 評估 Range header
  • 回傳完整檔案(200 OK)、部分內容(206 Partial Content)或無法滿足(416)
  • 有 body 的回應在串流關閉時刪除暫存檔;HEAD、416 與產生失敗在 build() 內刪除

驗證器:ZIP 每次請求都重新產生,entry 時間戳使兩次產生的位元組不同,因此不送 ETag; 帶 If-Range 的請求一律回完整內容,避免續傳時接上不同次產生的位元組。沒有 If-Range 的 Range 只對本次產生的檔案評估,跨請求拼接的一致性不保證——需要安全續傳時,先以 FileStorage 保存, 再以 FileResponseBuilder 下載。

只服務 GET 與 HEAD;其他方法在產生暫存檔之前丟出 IllegalArgumentException。

使用範例

@GetMapping("/products/{id}/images.zip")
public ResponseEntity<Resource> downloadImages(
        @PathVariable String id, HttpServletRequest request) {

    Product product = productService.findById(id);
    String partition = TenantContext.getCurrentTenantId();

    ZipFileResponseBuilder builder = ZipFileResponseBuilder.create("product-images.zip");

    // 新增主圖
    if (product.getMainImage() != null) {
        builder.addFile("main-image.jpg", fileStorage, partition,
                product.getMainImage().getFileId());
    }

    // 新增副圖
    int i = 1;
    for (FileDescriptor fd : product.getGalleryImages()) {
        builder.addFile("gallery-" + i++ + ".jpg", fileStorage, partition, fd.getFileId());
    }

    return builder.request(request).build();
}
See Also:
  • Method Details

    • create

      public static ZipFileResponseBuilder create(String zipFilename)
      建立 ZipFileResponseBuilder
      Parameters:
      zipFilename - ZIP 檔案名稱(如 "images.zip")
      Returns:
      ZipFileResponseBuilder 實例
    • addFile

      public ZipFileResponseBuilder addFile(String entryName, Supplier<InputStream> contentSupplier)
      新增檔案到 ZIP
      Parameters:
      entryName - ZIP 內的檔案名稱
      contentSupplier - InputStream 供應者
      Returns:
      this
    • addFile

      public ZipFileResponseBuilder addFile(String entryName, FileStorage fileStorage, String partition, String fileId)
      新增檔案到 ZIP(使用 FileStorage)
      Parameters:
      entryName - ZIP 內的檔案名稱
      fileStorage - FileStorage 實例
      partition - 儲存分區鍵
      fileId - 檔案 ID
      Returns:
      this
    • request

      public ZipFileResponseBuilder request(jakarta.servlet.http.HttpServletRequest request)
      由目前請求讀取方法、Range 與 If-Range
      Parameters:
      request - 目前請求
      Returns:
      this
    • method

      public ZipFileResponseBuilder method(org.springframework.http.HttpMethod method)

      設定請求方法;未設定時視為 GET

      只接受 GET 與 HEAD,其他方法在 build() 丟出 IllegalArgumentException。

      Parameters:
      method - 請求方法
      Returns:
      this
    • ifRange

      public ZipFileResponseBuilder ifRange(String ifRange)
      設定請求的 If-Range header;ZIP 沒有驗證器,出現任何值(含空值)都回完整內容
      Parameters:
      ifRange - 請求的 If-Range header 值;null 表示請求沒有 If-Range
      Returns:
      this
    • range

      public ZipFileResponseBuilder range(String rangeHeader)
      設定 Range header(支援部分內容下載)
      Parameters:
      rangeHeader - HTTP Range header 值(如 "bytes=0-1000"),可為 null
      Returns:
      this
    • hasFiles

      public boolean hasFiles()
      檢查是否有檔案
      Returns:
      是否有檔案
    • getFileCount

      public int getFileCount()
      取得檔案數量
      Returns:
      檔案數量
    • build

      public org.springframework.http.ResponseEntity<org.springframework.core.io.Resource> build()

      建構 ResponseEntity

      產生 ZIP 暫存檔並回傳下載回應。支援 Range Request(見類別說明的驗證器限制)。

      Returns:
      ResponseEntity with Resource
      Throws:
      IllegalArgumentException - 請求方法不是 GET 或 HEAD