精講RestTemplate第6篇-檔案上傳下載與大檔案流式下載

字母哥部落格發表於2020-08-12

本文是精講RestTemplate第6篇,前篇的blog訪問地址如下:

RestTemplate是HTTP客戶端庫,所以為了使用RestTemplate進行檔案上傳和下載,需要我們先編寫服務端的支援檔案上傳和下載的程式。請參考我之前寫的一篇文章:SpringBoot實現本地儲存檔案上傳及提供HTTP訪問服務 。按照此文完成學習之後,可以獲得

  • 一個以訪問服務URI為"/upload”的檔案上傳服務端點
  • 服務端點上傳檔案成功後會返回一個HTTP連線,可以用來下載檔案。

下面我們就開始學習使用RestTemplate是HTTP客戶端庫,進行檔案的上傳與下載。

一、檔案上傳

寫一個單元測試類,來完成RestTemplate檔案上傳功能,具體實現細節參考程式碼註釋

@SpringBootTest
class UpDownLoadTests {

   @Resource
   private RestTemplate restTemplate;

   @Test
   void testUpload()  {
      // 檔案上傳服務上傳介面
      String url = "http://localhost:8888/upload";
      // 待上傳的檔案(存在客戶端本地磁碟)
      String filePath = "D:\\data\\local\\splash.png";

      // 封裝請求引數
      FileSystemResource resource = new FileSystemResource(new File(filePath));
      MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
      param.add("uploadFile", resource);  //服務端MultipartFile uploadFile
      //param.add("param1", "test");   //服務端如果接受額外引數,可以傳遞


      // 傳送請求並輸出結果
      System.out.println("--- 開始上傳檔案 ---");
      String result = restTemplate.postForObject(url, param, String.class);
      System.out.println("--- 訪問地址:" + result);
   }

}

輸出結果如下:

--- 開始上傳檔案 ---
--- 訪問地址:http://localhost:8888/2020/08/12/028b38f1-3f9b-4088-9bea-1af8c18cd619.png

檔案上傳之後,可以通過上面的訪問地址,在瀏覽器訪問。或者通過RestTemplate客戶端進行下載。

二、檔案下載

執行下列程式碼之後,被下載檔案url,會被正確的儲存到本地磁碟目錄targetPath。

@Test
void testDownLoad() throws IOException {
   // 待下載的檔案地址
   String url = "http://localhost:8888/2020/08/12/028b38f1-3f9b-4088-9bea-1af8c18cd619.png";
   ResponseEntity<byte[]> rsp = restTemplate.getForEntity(url, byte[].class);
   System.out.println("檔案下載請求結果狀態碼:" + rsp.getStatusCode());

   // 將下載下來的檔案內容儲存到本地
   String targetPath = "D:\\data\\local\\splash-down.png";
   Files.write(Paths.get(targetPath), Objects.requireNonNull(rsp.getBody(),
               "未獲取到下載檔案"));
}

這種下載方法實際上是將下載檔案一次性載入到客戶端本地記憶體,然後從記憶體將檔案寫入磁碟。這種方式對於小檔案的下載還比較適合,如果檔案比較大或者檔案下載併發量比較大,容易造成記憶體的大量佔用,從而降低應用的執行效率。

三、大檔案下載

這種下載方式的區別在於

  • 設定了請求頭APPLICATION_OCTET_STREAM,表示以流的形式進行資料載入
  • RequestCallback 結合File.copy保證了接收到一部分檔案內容,就向磁碟寫入一部分內容。而不是全部載入到記憶體,最後再寫入磁碟檔案。
@Test
void testDownLoadBigFile() throws IOException {
   // 待下載的檔案地址
   String url = "http://localhost:8888/2020/08/12/028b38f1-3f9b-4088-9bea-1af8c18cd619.png";
   // 檔案儲存的本地路徑
   String targetPath = "D:\\data\\local\\splash-down-big.png";
   //定義請求頭的接收型別
   RequestCallback requestCallback = request -> request.getHeaders()
               .setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
   //對響應進行流式處理而不是將其全部載入到記憶體中
   restTemplate.execute(url, HttpMethod.GET, requestCallback, clientHttpResponse -> {
      Files.copy(clientHttpResponse.getBody(), Paths.get(targetPath));
      return null;
   });
}

歡迎關注我的部落格,裡面有很多精品合集

  • 本文轉載註明出處(必須帶連線,不能只轉文字):字母哥部落格

覺得對您有幫助的話,幫我點贊、分享!您的支援是我不竭的創作動力! 。另外,筆者最近一段時間輸出瞭如下的精品內容,期待您的關注。

相關文章