亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.430618.com 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

目前,網上一搜SpringBoot環境下載文件。有多種實現方式,大概率出來的會是基礎版的,基礎版的有幾個坑,我這里分別將基礎版以及基礎版會出現的問題,從而引申各種解決方法。

基礎版

話不多說,直接上源碼:

@RestController
public class TestDownload {
    @Value("${gen.base.path}")
    private String baseFilePath;
    @ApiOperation(value = "SpringBoot實現文件下載", notes = "基礎版")
    @RequestMApping(value = "/baseDownload", method = RequestMethod.GET)
    @ResponseBody
   public ResponseEntity<InputStreamResource> baseDownload(@RequestParam("fileId") String fileId) throws Exception {
        FileSystemResource file = new FileSystemResource(baseFilePath+fileId+".pdf");
        if (!file.exists()) {
        throw new HaBizException(1,"請您輸入正確的文件ID");
    }
        HttpHeaders headers = new HttpHeaders();
        headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
        headers.add("Content-Disposition", String.format("attachment; filename=%s", file.getFilename()));
        headers.add("Pragma", "no-cache");
        headers.add("Expires", "0");
        return ResponseEntity
                .ok()
                .headers(headers)
                .contentLength(file.contentLength())
                .contentType(MediaType.parseMediaType("application/octet-stream"))
                .body(new InputStreamResource(file.getInputStream()));
    }

}

這個基礎版是有兩個問題:

1、不能手動(主動)關閉文件流
2、下載文件較大時,jvm會內存溢出。

2. 進階版

主動關閉文件流。

@ApiOperation(value = "SpringBoot實現文件下載", notes = "進階版")
@RequestMapping(value = "/advancedDownload", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<StreamingResponseBody> advancedDownload(@RequestParam("fileId") String fileId) throws Exception {
    FileSystemResource file = new FileSystemResource(baseFilePath+fileId);
    if (!file.exists()) {
        throw  new HaBizException(1,"請您輸入正確的文件ID");
    }
    InputStream inputStream = file.getInputStream();
    StreamingResponseBody responseBody = outputStream -> {
        int numberOfBytesToWrite;
        byte[] data = new byte[1024];
        while ((numberOfBytesToWrite = inputStream.read(data, 0, data.length)) != -1) {
            outputStream.write(data, 0, numberOfBytesToWrite);
        }
        inputStream.close();
    };
    HttpHeaders headers = new HttpHeaders();
    headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
    headers.add("Content-Disposition", String.format("attachment; filename=%s", file.getFilename()));
    headers.add("Pragma", "no-cache");
    headers.add("Expires", "0");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_OCTET_STREAM)
            .body(responseBody);
}

這個版本普遍適用,但是仍然不能解決下載文件較大導致內存溢出的問題,所以這里就來個功能更全一點的,使用緩存流,邊讀邊寫

3. 高級版

使用緩存流,邊讀邊寫

@ApiOperation(value = "SpringBoot實現文件下載", notes = "使用緩存流,邊讀邊寫")
@RequestMapping(value = "/cacheDownload", method = RequestMethod.GET)
@ResponseBody
public void cacheDownload(@RequestParam("fileId") String fileId, HttpServletResponse response) throws Exception {
    FileSystemResource file = new FileSystemResource(baseFilePath+fileId);
    if (!file.exists()) {
        throw  new HaBizException(1,"請您輸入正確的文件ID");
    }
    String filename = file.getFilename();
    InputStream inputStream = null;
    BufferedInputStream bufferedInputStream = null;
    BufferedOutputStream bufferedOutputStream = null;
    response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
    try {
        inputStream = file.getInputStream();
        bufferedInputStream = new BufferedInputStream(inputStream);
        bufferedOutputStream = new BufferedOutputStream(response.getOutputStream());
        FileCopyUtils.copy(bufferedInputStream, bufferedOutputStream);
        }catch(Exception e){
            throw  new HaBizException(1,"下載文件異常"+e);
        }finally {
            if(null!=inputStream){
                inputStream.close();
            }
            if(null!=bufferedInputStream){
                bufferedInputStream.close();
            }
            if(null!=bufferedOutputStream){
                bufferedOutputStream.flush();
                bufferedOutputStream.close();
            }
    }
}

當然,如果不想使用JAVA自帶的BufferedInputStream當緩沖區的話,也可以自己寫,例子如下

@RequestMapping("/baseCacheDownload")
public void baseCacheDownload(@RequestParam("fileId") String fileId, HttpServletResponse response) throws Exception {
    FileSystemResource file = new FileSystemResource(baseFilePath+fileId);
    if (!file.exists()) {
        throw  new HaBizException(1,"請您輸入正確的文件ID");
    }
    InputStream inputStream = file.getInputStream();// 文件的存放路徑
    response.reset();
    response.setContentType("application/octet-stream");
    String filename = file.getFilename();
    response.addHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(filename, "UTF-8"));//①tips
    ServletOutputStream outputStream = response.getOutputStream();
    byte[] b = new byte[1024];
    int len;
    //緩沖區(自己可以設置大小):從輸入流中讀取一定數量的字節,并將其存儲在緩沖區字節數組中,讀到末尾返回-1
    while ((len = inputStream.read(b)) > 0) {
        outputStream.write(b, 0, len);
    }
    inputStream.close();
}

這里有一個技巧,

①tips處的代碼,Content-disposition 為屬性名。
attachment 表示以附件方式下載。
如果要在頁面中打開,則改為 inline。

filename 如果為中文,則會出現亂碼。
解決辦法有兩種:
1、 使用 fileName = new String(fileName.getBytes(), “ISO8859-1”) 語句
2、使用 fileName = HttpUtility.UrlEncode(filename, System.Text.Encoding.UTF8) 語句

分享到:
標簽:SpringBoot
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定