最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot返回文件讓前端下載的幾種方式

 更新時(shí)間:2025年12月01日 11:47:32   作者:N***p365  
文章介紹了開(kāi)發(fā)中文件下載的兩種常見(jiàn)解決方案,并詳細(xì)描述了通過(guò)后端進(jìn)行下載的原理和步驟,包括一次性讀取到內(nèi)存和分塊寫入響應(yīng)輸出流兩種方法,此外,還提供了從網(wǎng)絡(luò)上獲取文件和文本并下載的示例,并總結(jié)了InputStream和OutputStream的區(qū)別,感興趣的朋友跟隨小編一起看看吧

01 背景

在后端開(kāi)發(fā)中,通常會(huì)有文件下載的需求,常用的解決方案有兩種:

  1. 不通過(guò)后端應(yīng)用,直接使用nginx直接轉(zhuǎn)發(fā)文件地址下載(適用于一些公開(kāi)的文件,因?yàn)檫@里不需要授權(quán))
  2. 通過(guò)后端進(jìn)行下載,同時(shí)進(jìn)行一些業(yè)務(wù)處理

本篇主要以方法2進(jìn)行介紹,方法2的原理步驟如下:

  1. 讀取文件,得到文件的字節(jié)流
  2. 將字節(jié)流寫入到響應(yīng)輸出流中

02 一次性讀取到內(nèi)存,通過(guò)響應(yīng)輸出流輸出到前端

    @GetMapping("/file/download")
    public void fileDownload(HttpServletResponse response, @RequestParam("filePath") String filePath) {
        File file = new File(filePath);
        if (!file.exists()) {
            throw new BusinessException("當(dāng)前下載的文件不存在,請(qǐng)檢查路徑是否正確");
        }
        // 將文件寫入輸入流
        try (InputStream is = new BufferedInputStream(Files.newInputStream(file.toPath()))) {
            // 一次性讀取到內(nèi)存中
            byte[] buffer = new byte[is.available()];
            int read = is.read(buffer);
            // 清空 response
            response.reset();
            response.setCharacterEncoding("UTF-8");
            // Content-Disposition的作用:告知瀏覽器以何種方式顯示響應(yīng)返回的文件,用瀏覽器打開(kāi)還是以附件的形式下載到本地保存
            // attachment表示以附件方式下載   inline表示在線打開(kāi)   "Content-Disposition: inline; filename=文件名.mp3"
            // filename表示文件的默認(rèn)名稱,因?yàn)榫W(wǎng)絡(luò)傳輸只支持URL編碼的相關(guān)支付,因此需要將文件名URL編碼后進(jìn)行傳輸,前端收到后需要反編碼才能獲取到真正的名稱
            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
            // 告知瀏覽器文件的大小
            response.addHeader("Content-Length", "" + file.length());
            OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/octet-stream");
            outputStream.write(buffer);
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

適用于小文件,如果文件過(guò)大,一次性讀取到內(nèi)存中可能會(huì)出現(xiàn)oom的問(wèn)題

02 將文件流通過(guò)循環(huán)寫入到響應(yīng)輸出流中(推薦)

    @GetMapping("/file/download")
    public void fileDownload(HttpServletResponse response, @RequestParam("filePath") String filePath) {
        File file = new File(filePath);
        if (!file.exists()) {
            throw new BusinessException("當(dāng)前下載的文件不存在,請(qǐng)檢查路徑是否正確");
        }
        // 清空 response
        response.reset();
        response.setCharacterEncoding("UTF-8");
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
        response.setContentType("application/octet-stream");
        // 將文件讀到輸入流中
        try (InputStream is = new BufferedInputStream(Files.newInputStream(file.toPath()))) {
            OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
            byte[] buffer = new byte[1024];
            int len;
            //從輸入流中讀取一定數(shù)量的字節(jié),并將其存儲(chǔ)在緩沖區(qū)字節(jié)數(shù)組中,讀到末尾返回-1
            while((len = is.read(buffer)) > 0){
                outputStream.write(buffer, 0, len);
            }
            outputStream.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

03 從網(wǎng)絡(luò)上獲取文件并返回給前端

    @GetMapping("/net/download")
    public void netDownload(HttpServletResponse response, @RequestParam("fileAddress") String fileAddress, @RequestParam("filename") String filename) {
        try {
            URL url = new URL(fileAddress);
            URLConnection conn = url.openConnection();
            InputStream inputStream = conn.getInputStream();
            response.reset();
            response.setContentType(conn.getContentType());
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(filename, "UTF-8"));
            byte[] buffer = new byte[1024];
            int len;
            OutputStream outputStream = response.getOutputStream();
            while ((len = inputStream.read(buffer)) > 0) {
                outputStream.write(buffer, 0, len);
            }
            inputStream.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

04 從網(wǎng)絡(luò)上獲取文本并下載到本地

    @GetMapping("/netDownloadLocal")
    public void downloadNet(@RequestParam("netAddress") String netAddress, @RequestParam("filepath") String filepath) {
        try {
            URL url = new URL(netAddress);
            URLConnection conn = url.openConnection();
            InputStream inputStream = conn.getInputStream();
            FileOutputStream fileOutputStream = new FileOutputStream(filepath);
            int byteread;
            byte[] buffer = new byte[1024];
            while ((byteread = inputStream.read(buffer)) != -1) {
                fileOutputStream.write(buffer, 0, byteread);
            }
            fileOutputStream.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

05 總結(jié)

一定要搞清楚InputStreamOutputStream的區(qū)別,如果搞不清楚的,可以和字符流進(jìn)行映射,InputStream -> Reader,OutPutStream -> Writer,換成這樣你就知道讀取內(nèi)容需要使用Reader,寫入需要使用Writer了。

返回給前端的是輸出流,不需要你顯示的去返回(return response;),這樣會(huì)報(bào)錯(cuò)

到此這篇關(guān)于SpringBoot返回文件讓前端下載的幾種方式的文章就介紹到這了,更多相關(guān)springboot文件下載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java 二維數(shù)組矩陣乘法的實(shí)現(xiàn)方法

    java 二維數(shù)組矩陣乘法的實(shí)現(xiàn)方法

    java 二維數(shù)組矩陣乘法的實(shí)現(xiàn)方法,需要的朋友可以參考一下
    2013-03-03
  • Java編程讀寫鎖詳解

    Java編程讀寫鎖詳解

    本篇文章給大家詳細(xì)分享了Java編程讀寫鎖的相關(guān)原理以及知識(shí)點(diǎn)內(nèi)容,有興趣的朋友們可以參考下。
    2018-08-08
  • Java Collection 體系與使用場(chǎng)景多角度分析

    Java Collection 體系與使用場(chǎng)景多角度分析

    本文從抽象層級(jí)、接口設(shè)計(jì)和實(shí)際使用場(chǎng)景三個(gè)角度,系統(tǒng)介紹了Java Collection框架,文章詳細(xì)說(shuō)明了Collection的基本概念、Collection在體系中的位置、為什么要有Collection接口以及在不同場(chǎng)景下的使用建議,感興趣的朋友跟隨小編一起看看吧
    2026-01-01
  • Java快速實(shí)現(xiàn)短信登錄的詳細(xì)流程

    Java快速實(shí)現(xiàn)短信登錄的詳細(xì)流程

    短信登錄是基于短信驗(yàn)證碼的身份驗(yàn)證方式,在許多網(wǎng)站和應(yīng)用中被廣泛使用,通常被認(rèn)為比傳統(tǒng)的用戶名和密碼更安全,因?yàn)轵?yàn)證碼是一次性使用的,且只有用戶能夠接收到短信,本文給大家介紹了Java快速實(shí)現(xiàn)短信登錄的詳細(xì)流程,需要的朋友可以參考下
    2025-08-08
  • SpringBoot 集成 Statemachine的實(shí)戰(zhàn)指南

    SpringBoot 集成 Statemachine的實(shí)戰(zhàn)指南

    本文介紹了Spring State Machine框架的基本概念、核心特性、注解驅(qū)動(dòng)開(kāi)發(fā)方式以及如何在Spring Boot項(xiàng)目中集成狀態(tài)機(jī),通過(guò)狀態(tài)機(jī),可以有效地管理復(fù)雜的狀態(tài)流轉(zhuǎn)邏輯,文章還討論了狀態(tài)機(jī)的持久化問(wèn)題,并提供了一個(gè)自定義持久化實(shí)現(xiàn)的示例,感興趣的朋友跟隨小編一起看看吧
    2026-01-01
  • MyBatis實(shí)現(xiàn)注冊(cè)及獲取Mapper

    MyBatis實(shí)現(xiàn)注冊(cè)及獲取Mapper

    本文主要介紹了MyBatis實(shí)現(xiàn)注冊(cè)及獲取Mapper,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-03-03
  • 關(guān)于Java中的mysql時(shí)區(qū)問(wèn)題詳解

    關(guān)于Java中的mysql時(shí)區(qū)問(wèn)題詳解

    這篇文章主要給大家介紹了關(guān)于Java中mysql時(shí)區(qū)問(wèn)題的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • Java基于JDK 1.8的LinkedList源碼詳析

    Java基于JDK 1.8的LinkedList源碼詳析

    這篇文章主要給大家介紹了關(guān)于Java基于JDK 1.8的LinkedList源碼的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • Mybatis使用IN語(yǔ)句查詢的實(shí)現(xiàn)

    Mybatis使用IN語(yǔ)句查詢的實(shí)現(xiàn)

    這篇文章主要介紹了Mybatis使用IN語(yǔ)句查詢的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Java實(shí)現(xiàn)高效PDF文件傳輸技巧

    Java實(shí)現(xiàn)高效PDF文件傳輸技巧

    你是否曾為PDF文件傳輸?shù)牡托识鄲??現(xiàn)在,有了這份Java實(shí)現(xiàn)高效PDF文件傳輸技巧指南,你將能夠輕松解決這個(gè)問(wèn)題,我們將分享一些實(shí)用的技巧和最佳實(shí)踐,幫助你優(yōu)化文件傳輸過(guò)程,不要錯(cuò)過(guò)這個(gè)提高工作效率的機(jī)會(huì),快來(lái)閱讀這份指南吧!
    2024-03-03

最新評(píng)論

镇安县| 衡山县| 巍山| 宜兰县| 东明县| 丰县| 土默特左旗| 望都县| 资中县| 揭阳市| 东台市| 盱眙县| 富蕴县| 昂仁县| 平舆县| 赤城县| 垫江县| 信丰县| 涞水县| 岑溪市| 和林格尔县| 马鞍山市| 宁都县| 宝坻区| 德江县| 二连浩特市| 通州市| 瓮安县| 南召县| 夏邑县| 襄汾县| 沙坪坝区| 郸城县| 天峻县| 瑞昌市| 昭平县| 漠河县| 叙永县| 陇西县| 淳安县| 雷波县|