SpringBoot下载文件的正确方式~
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下载文件的正确方式~相关推荐
- Springboot 下载文件
Springboot下载文件比较简单,以下是代码: 目录结构 FileUtil为文件工具类,里面包括下载的方法,以下为FileUtil的代码: public class FileUtil {publi ...
- 打开Shapefile文件的正确方式
打开Shapefile文件的正确方式 作者:阿振 邮箱:tanzhenyugis@163.com 博客:https://blog.csdn.net/theonegis/article/details/ ...
- javascript下载文件几种方式,接收后台返回流下载或直接下载文件
目录 1 javascript下载文件7中方式 1.1 window.location.href下载 1.2 window.location下载 1.3 iframe下载 1.4 form表单的形式下 ...
- .net 下载文件几种方式
方式一:TransmitFile实现下载.将指定的文件直接写入 HTTP 响应输出流,而不在内存中缓冲该文件. protected void Button1_Click(object sender, ...
- JS 下载文件两种方式总结
后端返回Blob对象(文件流),完成导出.下载功能: 1.介绍Blob Blob Blob 对象表示一个不可变.原始数据的类文件对象.它的数据可以按文本或二进制的格式进行读取,也可以转换成 Reada ...
- Asp.Net 之 下载文件的常用方式
1.直接使用Response.TransmitFile(filename)方法 protected void Button_Click(object sender, EventArgs e){/*微软 ...
- asp.net下载文件几种方式
本文转载自:http://www.cnblogs.com/weixing/archive/2012/02/27/2369567.html protected void Button1_Click(ob ...
- SpringBoot下载文件打不开的解决办法
吸取教训主要是是下载文件打不开,是因为当前页面输入流不能直接连接打开.需要新的连接进行打开点击下载. http://localhost:8081/tm/corpus/infomation/downlo ...
- Linux上传文件和下载文件命令行方式
在Linux主机上,安装上传下载工具包rz及sz 只需要安装下面这个包即可,执行下面的安装命令 yum install -y lrzsz 上传 在Linux命令行下输入rz, rz 1 输入rz命令后 ...
最新文章
- sql 怎样 得到 的客户端的ip地址_怎样用卷发棒?正确用法大揭密-装修攻略
- nidlist 问题
- Syntax error, parameterized types are only available if source level is 1.5
- Java之杨辉三角的实现
- 计算机用户登录,计算机术语:密码、用户、登录
- 游戏外挂是怎么炼成的
- Android 内容提供器---简介
- chrome axure 插件安装
- vue当前浏览器是否为ie_vue判断当前浏览器为IE低版本,给出升级提示;IE11及其他浏览器正常使用...
- android桌面,Android Q带来全新桌面模式
- 银行圈巨变!中国建设银行无人银行开业!
- 2020年HS芯片说明海思论坛
- linux: It seems that scikit-learn has not been built correctly.
- 【模板】线段树 2 洛谷P3373
- 在IPCAM上实现RTSP协议直播-live555
- 成都富华力鼎:抖音的商品标题怎么写
- 智能家居隐私泄露严重!我们该如何应对?
- 中国银河证券公募基金分类体系的理论依据与规则基础
- checkbox 选中触发js事件
- word中怎样设置行距行高