文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

SpringBoot下载文件的正确方式~

2023-08-23 19:27

关注

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统一处理:

@RestControllerAdvicepublic class ExceptionAdvice {    private static final Logger logger = LoggerFactory.getLogger(ExceptionAdvice.class);        @ExceptionHandler(value = BindException.class)    public ResponseEntity<Result<Object>> handleValidateException(BindException bindException) {        logger.error("数据绑定异常,{}", bindException.getMessage(), bindException);        return of(HttpStatus.BAD_REQUEST, "数据绑定异常");    }        @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());    }        @ExceptionHandler(value = OptErrorException.class)    public ResponseEntity<Result<Object>> handleOptErrorException(OptErrorException exception) {        return of(HttpStatus.INTERNAL_SERVER_ERROR, exception.getOptMsg());    }        @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, "服务器内部未知错误");    }}

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

来源地址:https://blog.csdn.net/dubulingbo/article/details/129641709

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯