Spring Boot 配合 axios 实现文件下载功能

  • 前言
  • 比较一般的解法
    • 分析原因
  • 正确解法

前言

最近遇到一个奇怪的需求,前端通过post请求下载压缩文件,同时会传给后端一些数据,用于生成压缩包。此时后端接口就不仅仅是生成压缩文件流输出给前端。而必须要有报错能力与异常处理能力。即如果后端报错,前端应该是下载不了文件流。

比较一般的解法

一般而言,Spring Boot生成文件流供前端下载,会直接将文件流写入到 HttpServletResponse.getOutputStream(),然而这样会有一个问题,无论后端如何报错,前端都能成功下载文件,因为 status=200。即如下写法:

@PostMapping(value = "/project/code/download")
public void downloadCode(@RequestBody TProjectInfo pf, HttpServletResponse response) {// 1.生成源码文件// 2.压缩文件// 3.设置回复的一些参数// 4.将压缩文件写入网络流log.info("request param: {}", pf);OutputStream os = null;try {// 配置文件下载// 下载文件能正常显示中文String filename = pf.getProjectName() + System.currentTimeMillis() + ".zip";response.setHeader("Content-Disposition", "attachment;filename=" + filename);response.setHeader("Content-Type", "application/octet-stream");response.setContentType("application/octet-stream; charset=UTF-8");os = response.getOutputStream();projectService.generateCode(pf, os);log.info("Download  successfully!");} catch (Exception e) {log.error("Download  failed: {}", e.getMessage());throw new OptErrorException(OptStatus.FAIL.code, "文件下载失败");} finally {if (os != null) {try {os.close();} catch (IOException e) {e.printStackTrace();}}}
}

分析原因

因为后端直接向OutputStream写入,会覆盖所有异常捕获,因此前端直接向data下取字节流数据即可。

正确解法

其实就是要后端能在错误时返回json数据,正确下载时直接取data下取字节流即可,所以使用 ResponseEntity 返回即可。

@PostMapping(value = "/project/code/download")
public ResponseEntity<InputStreamResource> downloadCode(@RequestBody TProjectInfo pf) {log.info("request param: {}", pf);String filename = pf.getProjectName() + System.currentTimeMillis() + ".zip";byte[] bytes = projectService.generateCode(pf);ByteArrayInputStream bais = new ByteArrayInputStream(bytes);HttpHeaders headers = new HttpHeaders();headers.add("Content-Disposition", String.format("attachment; filename=\"%s\"", filename));return ResponseEntity.ok().headers(headers).contentType(MediaType.parseMediaType("application/octet-stream")).body(new InputStreamResource(bais));
}

这里的异常,使用RestExceptionAdvice统一处理:

@RestControllerAdvice
public class ExceptionAdvice {private static final Logger logger = LoggerFactory.getLogger(ExceptionAdvice.class);/*** 处理数据绑定异常** @param bindException 数据绑定异常* @return 统一响应基本结果*/@ExceptionHandler(value = BindException.class)public ResponseEntity<Result<Object>> handleValidateException(BindException bindException) {logger.error("数据绑定异常,{}", bindException.getMessage(), bindException);return of(HttpStatus.BAD_REQUEST, "数据绑定异常");}/*** 统一处理 405 异常** @param exception 请求方法不支持异常* @return 统一响应结果*/@ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)public ResponseEntity<Result<Object>> handleMethodNotSupportedException(HttpRequestMethodNotSupportedException exception) {if (exception != null) {logger.error("Http 405, {}", exception.getMessage(), exception);}return of(HttpStatus.METHOD_NOT_ALLOWED, "方法不被支持");}private ResponseEntity<Result<Object>> of(HttpStatus status, String msg) {return ResponseEntity.status(status).body(Result.builder().code(OptStatus.FAIL.code).msg(msg).build());}/*** 统一处理自定义操作错误异常** @param exception 操作错误异常* @return 统一响应结果*/@ExceptionHandler(value = OptErrorException.class)public ResponseEntity<Result<Object>> handleOptErrorException(OptErrorException exception) {return of(HttpStatus.INTERNAL_SERVER_ERROR, exception.getOptMsg());}/*** 统一处理 服务器内部 异常** @param e 异常* @return 统一响应结果*/@ExceptionHandler(value = Throwable.class)public ResponseEntity<Result<Object>> handle500(Throwable e) {if (e != null) {logger.error("Http 500, {}", e.getMessage(), e);}return of(HttpStatus.INTERNAL_SERVER_ERROR, "服务器内部未知错误");}}

以上就是解决的全过程,可能写得有点片面,纯属一点个人实践中的见解。欢迎各位交流学习!

SpringBoot下载文件的正确方式~相关推荐

  1. Springboot 下载文件

    Springboot下载文件比较简单,以下是代码: 目录结构 FileUtil为文件工具类,里面包括下载的方法,以下为FileUtil的代码: public class FileUtil {publi ...

  2. 打开Shapefile文件的正确方式

    打开Shapefile文件的正确方式 作者:阿振 邮箱:tanzhenyugis@163.com 博客:https://blog.csdn.net/theonegis/article/details/ ...

  3. javascript下载文件几种方式,接收后台返回流下载或直接下载文件

    目录 1 javascript下载文件7中方式 1.1 window.location.href下载 1.2 window.location下载 1.3 iframe下载 1.4 form表单的形式下 ...

  4. .net 下载文件几种方式

    方式一:TransmitFile实现下载.将指定的文件直接写入 HTTP 响应输出流,而不在内存中缓冲该文件. protected void Button1_Click(object sender, ...

  5. JS 下载文件两种方式总结

    后端返回Blob对象(文件流),完成导出.下载功能: 1.介绍Blob Blob Blob 对象表示一个不可变.原始数据的类文件对象.它的数据可以按文本或二进制的格式进行读取,也可以转换成 Reada ...

  6. Asp.Net 之 下载文件的常用方式

    1.直接使用Response.TransmitFile(filename)方法 protected void Button_Click(object sender, EventArgs e){/*微软 ...

  7. asp.net下载文件几种方式

    本文转载自:http://www.cnblogs.com/weixing/archive/2012/02/27/2369567.html protected void Button1_Click(ob ...

  8. SpringBoot下载文件打不开的解决办法

    吸取教训主要是是下载文件打不开,是因为当前页面输入流不能直接连接打开.需要新的连接进行打开点击下载. http://localhost:8081/tm/corpus/infomation/downlo ...

  9. Linux上传文件和下载文件命令行方式

    在Linux主机上,安装上传下载工具包rz及sz 只需要安装下面这个包即可,执行下面的安装命令 yum install -y lrzsz 上传 在Linux命令行下输入rz, rz 1 输入rz命令后 ...

最新文章

  1. sql 怎样 得到 的客户端的ip地址_怎样用卷发棒?正确用法大揭密-装修攻略
  2. nidlist 问题
  3. Syntax error, parameterized types are only available if source level is 1.5
  4. Java之杨辉三角的实现
  5. 计算机用户登录,计算机术语:密码、用户、登录
  6. 游戏外挂是怎么炼成的
  7. Android 内容提供器---简介
  8. chrome axure 插件安装
  9. vue当前浏览器是否为ie_vue判断当前浏览器为IE低版本,给出升级提示;IE11及其他浏览器正常使用...
  10. android桌面,Android Q带来全新桌面模式
  11. 银行圈巨变!中国建设银行无人银行开业!
  12. 2020年HS芯片说明海思论坛
  13. linux: It seems that scikit-learn has not been built correctly.
  14. 【模板】线段树 2 洛谷P3373
  15. 在IPCAM上实现RTSP协议直播-live555
  16. 成都富华力鼎:抖音的商品标题怎么写
  17. 智能家居隐私泄露严重!我们该如何应对?
  18. 中国银河证券公募基金分类体系的理论依据与规则基础
  19. checkbox 选中触发js事件
  20. word中怎样设置行距行高

热门文章

  1. MOOS-ivp app发布车辆位置及控制车辆运动
  2. 投资学U09 资本资产定价模型 习题笔记
  3. RTX3060显卡比1060跑深度学习慢?
  4. C. Alice and the Cake
  5. sql数据库去重语法_oracle大数据去重sql语句
  6. 【深度学习】深度学习如何影响运筹学?
  7. 分散染料对涤纶织物染色步骤
  8. 苹果13防水吗 苹果13颜色哪个好看
  9. 【汇正财经】股本的法律规范
  10. linux开机磁盘检查挂载失败 ,导致无法进入系统