SpringMVC,SpringBoot文件下載


前言

最近嚴查security, 導致原來暴露出去的s3不能用了,不允許public的s3,暫時的折中方案是自己做跳轉。於是需要在SpringMVC中實現文件下載功能。

關於文件存儲的設計

文件存儲通常用作對象存儲,業界標准就是AWS s3, 國內的七牛也差不多。不想自建的話,采用這種第三方存儲是很方便的。但是,有寫地方需要注意。

安全問題

就像這次整改遇到的,權限問題大概是對象存儲必須具備的。s3的權限特別多和復雜,可以做到認證user訪問; 指定ip訪問; 指定IAM Role訪問; 指定第三方登陸比如Facebook,google的認證,設置自己的認證,這里是指Cognito。

地址路徑的健壯性

review代碼的時候發現了幾個嚴重的問題,地址問題尤為重要,簡直就是bug一樣。首先,db存儲的文件路徑不應該包含域名前綴,像這次整改圖片存儲就導致以前db里的數據不能用了。db只能存儲相對路徑,即當指定改類型前綴后,變化的部分路徑。。 然后就是 需要一個域名,對於公開的地址,需要一個域名來維護,而不是直接指定當前的文件服務器。比如一個公開的s3可能是這樣的:https://mybucket.s3.amazonaws.com/keyprefix/key. 如果我們變更了s3的bucket,那么這個地址就廢棄了,這個很有可能發生的。因此,用一個我們自己的域名指向s3可以屏蔽這個細節。同理,如果寫死了文件服務器的地址,當文件服務器變更的時候,公開的文件將全部失效。

如何使用SpringMVC下載文件

我們可以簡單的在HttpServletResponse的OutputStream里寫入我們的文件流,這樣就可以實現文件下載。但這個做法感覺有點太直接了,推薦使用Spring的ResponseEntity來做。

@RequestMapping(value = "/static/filename")
public ResponseEntity<InputStreamResource>(HttpServletResponse response) {
    final ObjectMetadata objectMetadata = s3Object.getObjectMetadata();

    return ResponseEntity.ok()
            .header("Access-Control-Allow-Origin", "*")
            .cacheControl(CacheControl.maxAge(maxAge, TimeUnit.DAYS).cachePublic())
            .allow(HttpMethod.GET, HttpMethod.OPTIONS)
            .contentLength(objectMetadata.getContentLength())
            .contentType(MediaType.valueOf(objectMetadata.getContentType()))
            .body(new InputStreamResource(s3Object.getObjectContent()));
}
  1. 問題核心在於返回ResponseEntity<InputStreamResource>
  2. ResponseEntity是SpringMVC里統一封裝的返回值response信息
  3. InputStreamResource則是接收一個輸入流InputStream的結果集
  4. 然后可以設置瀏覽器緩存,這個對用戶刷新頁面挺重要的
  5. 對於圖片和js等,需要設置contentType為png或者js等


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM