当前位置:首页 » 《资源分享》 » 正文

SpringBoot返回文件让前端下载的几种方式

17 人参与  2024年11月16日 16:41  分类 : 《资源分享》  评论

点击全文阅读


01 背景

在后端开发中,通常会有文件下载的需求,常用的解决方案有两种:

不通过后端应用,直接使用nginx直接转发文件地址下载(适用于一些公开的文件,因为这里不需要授权)通过后端进行下载,同时进行一些业务处理

本篇主要以方法2进行介绍,方法2的原理步骤如下:

读取文件,得到文件的字节流将字节流写入到响应输出流中

02 一次性读取到内存,通过响应输出流输出到前端

    @GetMapping("/file/download")    public void fileDownload(HttpServletResponse response, @RequestParam("filePath") String filePath) {        File file = new File(filePath);        if (!file.exists()) {            throw new BusinessException("当前下载的文件不存在,请检查路径是否正确");        }        // 将文件写入输入流        try (InputStream is = new BufferedInputStream(Files.newInputStream(file.toPath()))) {                        // 一次性读取到内存中            byte[] buffer = new byte[is.available()];            int read = is.read(buffer);            // 清空 response            response.reset();            response.setCharacterEncoding("UTF-8");            // Content-Disposition的作用:告知浏览器以何种方式显示响应返回的文件,用浏览器打开还是以附件的形式下载到本地保存            // attachment表示以附件方式下载   inline表示在线打开   "Content-Disposition: inline; filename=文件名.mp3"            // filename表示文件的默认名称,因为网络传输只支持URL编码的相关支付,因此需要将文件名URL编码后进行传输,前端收到后需要反编码才能获取到真正的名称            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);        }    }

适用于小文件,如果文件过大,一次性读取到内存中可能会出现oom的问题

02 将文件流通过循环写入到响应输出流中(推荐)

    @GetMapping("/file/download")    public void fileDownload(HttpServletResponse response, @RequestParam("filePath") String filePath) {        File file = new File(filePath);        if (!file.exists()) {            throw new BusinessException("当前下载的文件不存在,请检查路径是否正确");        }        // 清空 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;            //从输入流中读取一定数量的字节,并将其存储在缓冲区字节数组中,读到末尾返回-1            while((len = is.read(buffer)) > 0){                outputStream.write(buffer, 0, len);            }            outputStream.close();        } catch (IOException e) {            throw new RuntimeException(e);        }    }

03 从网络上获取文件并返回给前端

    @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 从网络上获取文本并下载到本地

    @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 总结

一定要搞清楚 InputStreamOutputStream的区别,如果搞不清楚的,可以和字符流进行映射,InputStream -> Reader,OutPutStream -> Writer,换成这样你就知道读取内容需要使用Reader,写入需要使用Writer了。

返回给前端的是输出流,不需要你显示的去返回(return response;),这样会报错


点击全文阅读


本文链接:http://zhangshiyu.com/post/187239.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1