Springboot 文件下载(Excel) + Vue前端下载按钮

看了网上的一些文件下载博客讲的太多了,我只想要完成这个事情,所以写一篇简洁一点的教程

我这里的代码是针对 Excel表格的,如果你是其它类型的文件就要看详细一点,如果你也是Excel

直接复制去用即可

我是把文件直接放到项目的 resources 文件夹下的

首先是后端,直接用流的方式把数据传给前端

java 复制代码
    @GetMapping("/downloadExcel2")
    public void downloadExcelTemplate2(HttpServletResponse response) throws IOException {
        ClassPathResource resource = new ClassPathResource("templates/成人服装信息导入模版3.xlsx");
        // 指定 xlsx 的 MIME
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

        // 按 RFC5987 编码中文文件名
        String filename = resource.getFilename();  // "成人服装信息导入模版3.xlsx"
        String encoded = URLEncoder.encode(filename, "UTF-8").replace("+", "%20");
        response.setHeader(
                "Content-Disposition",
                "attachment; filename*=UTF-8''" + encoded
        );

        try (InputStream in = resource.getInputStream(); OutputStream out = response.getOutputStream()) {
            byte[] buffer = new byte[8192];
            int len;
            while ((len = in.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
            // out.flush();  // 可选
        }
    }

返回类型直接用void,不用自己的统一返回格式

response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

上面这行的意思是这一行代码的作用是告诉浏览器(或任何客户端)------响应体中传输的数据属于哪种类型的文件,以便浏览器能正确地处理它。如果你是其他文件,你就搜一下某某文件的MIME 类型是什么,你自己修改一下即可,或者你可用通用的

复制代码
// 内容类型为通用类型,表示二进制数据流
response.setContentType("application/octet-stream");

response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + fileName);

上面这行的作用是浏览器在收到这个头后就会弹出下载对话框,并且默认的保存文件名就是你通过 fileName 给定的名字(包括中文也能正确显示)。

attachment; 告诉浏览器:不要尝试把响应当作页面内容渲染,而是触发"另存为"下载对话框。

filename*=UTF-8'' 是 RFC 5987 对非 ASCII 文件名(比如中文名)的一种标准编码方式。

+ fileName 就是你拼好的、已经 percent‑encode(%xx)过的 UTF‑8 文件名字符串。

因为我的文件名是中文的所以才这么写,如果你的是英文的可以直接用那两行注释里面的其中一行

前端:

java 复制代码
  return axios({
    url,//接口地址,或者还需要携带token的你可以自己加,一般都会封装有,我这里就是说个大概
    method: 'get',
    params,
    responseType: 'blob',          // 关键点:告诉 axios 返回 blob
  }).then(response => {
       // 处理文件下载响应
        const blob = new Blob([response], { type: 'application/octet-stream' });
        const downloadUrl = window.URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.href = downloadUrl;
        link.setAttribute('download', '服装信息导入模版.xlsx');
        document.body.appendChild(link);
        link.click();
        window.URL.revokeObjectURL(downloadUrl);
        document.body.removeChild(link);
        this.$message.success('下载成功');
      }).catch(error => {
        this.$message.error('下载失败: ' + (error.message || '未知错误'));
      });
      });

axios里面的请求的东西,重要的就是 responseType: 'blob',

then()返回的东西还是重点,直接复制过去修改一下就好了,

主要修改两处地方,改成你自己设置的

const blob = new Blob([response], { type: 'application/vnd.ms-excel' });

link.setAttribute('download', '成人服装信息导入模版.xls');


如果出现内容乱码的话

我建议文件名改用英文的,反正前端才是设置用户下载文件时的名字

后端就可以改成如下

复制代码
    @GetMapping("/downloadExcel2")
    public void downloadExcelTemplate2(HttpServletResponse response) throws IOException {
        // 使用ClassPathResource替代ResourceUtils.getFile(),这样打包后也能正常工作
        ClassPathResource resource = new ClassPathResource("/templates/recc.xlsx");

        // 检查资源是否存在
        if (!resource.exists()) {
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        // 获取文件名
        String filename = "recc.xlsx";

        // 设置响应头信息 
        response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");

        // 内容类型为通用类型,表示二进制数据流 
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

        // 循环,边读取边输出,可避免大文件时OOM 
        try (InputStream inputStream = resource.getInputStream();
             OutputStream os = response.getOutputStream()) {

            byte[] bytes = new byte[1024];
            int readLength;
            while ((readLength = inputStream.read(bytes)) != -1) {
                os.write(bytes, 0, readLength);
            }
            os.flush(); // 确保数据完全写入
        }
    }
相关推荐
于慨18 小时前
Lambda 表达式、方法引用(Method Reference)语法
java·前端·servlet
石小石Orz18 小时前
油猴脚本实现生产环境加载本地qiankun子应用
前端·架构
swg32132118 小时前
Spring Boot 3.X Oauth2 认证服务与资源服务
java·spring boot·后端
从前慢丶18 小时前
前端交互规范(Web 端)
前端
像我这样帅的人丶你还18 小时前
别再让JS耽误你进步了。
css·vue.js
gelald18 小时前
SpringBoot - 自动配置原理
java·spring boot·后端
@yanyu66618 小时前
07-引入element布局及spring boot完善后端
javascript·vue.js·spring boot
CHU72903518 小时前
便捷约玩,沉浸推理:线上剧本杀APP功能版块设计详解
前端·小程序
GISer_Jing18 小时前
Page-agent MCP结构
前端·人工智能
王霸天18 小时前
💥别再抄网上的Scale缩放代码了!50行源码教你写一个永不翻车的大屏适配
前端·vue.js·数据可视化