vue导出文件流获取附件名称并下载(在response.headers里解析filename导出)

news2024/11/22 5:33:02

导出文件流下载,拦截器统一处理配置

  • 需求
  • 以往实现的方法(各自的业务层写方法)
  • 现在实现的方法(axios里拦截器统一配置处理)
  • 把文章链接复制粘贴给后端,让大佬自己赏阅。

需求

  之前实现的导出都是各自的业务层,调用接口,使用blob对象转换,最终a标签导出,需要自定义文件名跟文件后缀。
  现在统一在拦截器配置,根据后端返回的response.headers解析是否是文件流,统一做配置处理,然后对后端返回的filename进行转码,后端统一配置文件名及类型。前端只管a标签下载即可。

以往实现的方法(各自的业务层写方法)

//数据导出
    indexExport() {
      let statYear = {
        statDate: this.form.statDate,
        dataType: "1",
      };
      let infoMsg = this.$notify.info({
        title: "消息",
        message: "正在下载文件,勿退出,请稍后",
        duration: 0,
      });
      gljyjcDataExport(statYear).then((res) => {
        infoMsg.close(); //下载成功,等待下载提示框关闭
        this.$notify({
          title: "成功",
          message: "下载完成",
          type: "success",
        });
        let blob = new Blob([res], {
          type: "",
        });
        let url = window.URL.createObjectURL(blob);
        const link = document.createElement("a"); // 创建a标签
        link.href = url;
        link.download = "数据清单(" + this.form.statDate + ").xlsx"; // 重命名文件
        link.click();
        URL.revokeObjectURL(url); // 释放内存
      });
    },

现在实现的方法(axios里拦截器统一配置处理)

主要看注释行“文件下载”,因为后端返回流文件时候携带的response.headers会多Content-Disposition这个字段。然后拿到里边的filename后,对filename包含的信息进行转码就可
decodeURIComponent、decodeURI都可进行转码,具体二者有啥区别,水平有限没大看懂,可自行百度查阅符合选项

//拦截器里肯定有请求拦截代码axios.interceptors.request。怕展示代码冗余就不多贴了
...
axios.interceptors.response.use(
    response => {
    
        const res = response.data;
        const config = response.config;
        console.log(response.headers,"response.headers")//这块可以看一下response.headers究竟是什么
        // 文件下载(主要看这块)
        if (response.headers['content-disposition']) {
            let downLoadMark = response.headers['content-disposition'].split(';');
            if (downLoadMark[0] === 'attachment') {
                // 执行下载
                let fileName = downLoadMark[1].split('filename=')[1];
                if (fileName) {
                    //fileName = decodeURIComponent(filename);//对filename进行转码
                    fileName = decodeURI(fileName);
                    if (window.navigator.msSaveOrOpenBlob) {
                        navigator.msSaveBlob(new Blob([res]), fileName);
                    } else {
                        let url = window.URL.createObjectURL(new Blob([res]));
                        let link = document.createElement('a');
                        link.style.display = 'none';
                        link.href = url;
                        link.setAttribute('download', fileName);
                        document.body.appendChild(link);
                        link.click();
                        return;
                    }
                } else {
                    return res;
                }
            }
        }

        // 全局异常处理(获取code做正常的拦截操作,根据自己的业务层code写符合的就可)
        if (res.code !== CODE_SUCCESS) {
            if (res.code == '205') {
                Message.error({ message: res.data || "登录失败" });
                store.dispatch("user/logout").then(() => {
                    window.location.reload();
                  });
                return
            }
            if (res.code === WARN_TIP) {
                Message.warning({
                    message: res.message
                });
            }

            if (res.code === LOGIN_FAIL) {
                Message.error({ message: res.message || "登录失败" });
            }
            // 其他状态码特殊处理
            return Promise.reject(new Error(res.message || "Error"));
        }

        return res;
    }, error => {
        // 防重复提交
        if (error.message) {
            allowRequest(reqList, error.message.url);
        }
        if (error.response) {
            if (error.response.data.code == 600 && !tipCode) {
                tipCode = true;
                Message.error({ message: '系统登录身份令牌失效,请重新登录!' });
            } else if (error.response.status == 500) {
                Message.error({ message: '系统异常' });
            }
        }
        return Promise.reject(error);
    }
);

在这里插入图片描述
在这里插入图片描述

以上是未解析之前浏览器看到的文件夹名
经过decodeURIComponent或decodeURI解析后,前端就能获取到后端返回的中文文件名了。

在这里插入图片描述

把文章链接复制粘贴给后端,让大佬自己赏阅。

截止目前,前端能干的活就到此为止了。
那么有人就想问了,那后端response.headers里没返回我想要的Content-Disposition,前端怎么捕获。
对此呢,我又找我们后端大佬要了一下后端实现的代码,我就原封不动贴出来了,因为我根本看不懂说的是什么意思

Controller端代码(啥是Controller,根本不懂)
 @PostMapping(value="/exportAddresses")
    public Result exportAddresses(HttpServletResponse response){
        String[] titles = new String[] {"id","tableCode","columnName"};
        List<Map<String,Object>> objList = new ArrayList<>();
        DownLoadFileController addressService;
        List<NpColumns> npColumnsList = npColumnsService.findByTableCode("APP_TASK_CASE_INFO");
        for(NpColumns item : npColumnsList){
            Map<String,Object> tempMap = new HashMap<>();
            tempMap.put("id", item.getId());
            tempMap.put("tableCode", item.getTableCode());
            tempMap.put("columnName", item.getColumnName());
            objList.add(tempMap);
        }
        try {
            FileUtils.exportExcel(response,"地址树",titles,objList);
            return ResultGenerator.genSuccessResult("导出成功!");
        }catch (Exception e){
            e.printStackTrace();
            return ResultGenerator.genFailResult("导出失败!");
        }
    }
工具类方法(啥是工具类,也不懂)
public static void exportExcel(HttpServletResponse response,String fileName,String[] titles,List<Map<String,Object>> result){
        HSSFWorkbook wb;
        OutputStream output = null;
        String tempName = fileName;
        try {
            Date date = new Date();
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            fileName +="_"+df.format(date)+".xls";
            String encodedFilename = URLEncoder.encode(fileName, "UTF-8");
            wb= new HSSFWorkbook();
            HSSFSheet sh = wb.createSheet();
            // 设置列宽
            for(int i = 0; i < titles.length-1; i++){
                sh.setColumnWidth( i, 256*15+184);
            }
            // 第一行表头标题,CellRangeAddress 参数:行 ,行, 列,列
            HSSFRow row = sh.createRow(0);
            HSSFCell cell = row.createCell(0);
            cell.setCellValue(new HSSFRichTextString(tempName));
            //cell.setCellStyle(fontStyle(wb));
            sh.addMergedRegion(new CellRangeAddress(0, 0, 0,titles.length-1));
            // 第二行
            HSSFRow row3 = sh.createRow(1);
            // 第二行的列
            for(int i=0; i < titles.length; i++){
                cell = row3.createCell(i);
                cell.setCellValue(new HSSFRichTextString(titles[i]));
                //cell.setCellStyle(fontStyle(wb));
            }
            //填充数据的内容  i表示行,z表示数据库某表的数据大小,这里使用它作为遍历条件
            int i = 2, z = 0;
            while (z < result.size()) {
                row = sh.createRow(i);
                Map<String,Object> map = result.get(z);
                for(int j=0;j < titles.length;j++) {
                    cell = row.createCell(j);
                    if(map.get(titles[j]) !=null) {
                        cell.setCellValue(map.get(titles[j]).toString());
                    }else {
                        cell.setCellValue("");
                    }
                }
                i++;
                z++;
            }
            output = response.getOutputStream();
            response.reset();
            response.addHeader("Content-Type","application/octet-stream;charset=utf-8");
            response.setHeader("Content-disposition", "attachment; filename="+encodedFilename);
            response.setContentType("application/msexcel");
            wb.write(output);
            output.flush();
            output.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
最后还有个中文处理乱码那块(这都是啥啥啥,还是不懂)
String encodedFilename = URLEncoder.encode(fileName, "UTF-8");设置文件名的中文编码
response.addHeader("Content-Type","application/octet-stream;charset=utf-8");//这里也设置了相同的编码格式
response.setHeader("Content-disposition", "attachment; filename="+encodedFilename);

大家有更好的实现方案话欢迎多交流

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/893008.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

两阶段提交:详解数据库宕机引起的主从不一致问题、redolog与binlog的两阶段提交

0、基础知识and问题 从基础上我们了解&#xff1a; &#xff08;1&#xff09;redolog作为数据库保证持久化的日志&#xff0c;在update事务提交后就会按一定的策略刷入磁盘中&#xff0c;在刷入后&#xff0c;即使数据库断电宕机&#xff0c;mysql也能从redolog中恢复数据到磁…

CentOS 7 安装MySQL8.0.33

一、查看 CentOS 版本 要查看当前 CentOS 版本&#xff0c;你可以执行以下命令&#xff1a; cat /etc/centos-release 该命令将显示当前 CentOS 的版本信息&#xff0c;例如&#xff1a; CentOS Linux release 7.9.2009 (Core) 在这个示例中&#xff0c;CentOS 版本为 7.…

Spring Clould 负载均衡 - Ribbon

视频地址&#xff1a;微服务&#xff08;SpringCloudRabbitMQDockerRedis搜索分布式&#xff09; Ribbon-负载均衡原理&#xff08;P14&#xff09; 具体实现时通过LoaBalanced注解实现&#xff0c;表示RestTemplate要被Ribbon拦截处理 orderservice调用user时候&#xff0c…

【无标题】QT应用编程: QtCreator配置Git版本控制(码云)

QT应用编程: QtCreator配置Git版本控制(码云) 感谢&#xff1a;DS小龙哥的文章&#xff0c;这篇主要参考小龙哥的内容。 https://cloud.tencent.com/developer/article/1930531?areaSource102001.15&traceIdW2mKALltGu5f8-HOI8fsN Qt Creater 自带了git支持。但是一直没…

如何使用CSS实现一个无限滚动效果(Infinite Scroll)?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 使用CSS实现无限滚动效果&#xff08;Infinite Scroll&#xff09;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xf…

接口测试及接口抓包常用测试工具和方法?

作为测试领域中不可或缺的一环&#xff0c;接口测试和抓包技术在软件开发过程中扮演着至关重要的角色。不论你是新手还是有一些经验的小伙伴&#xff0c;本篇文章都会为你详细介绍接口测试的基本概念、常用测试工具和实际操作技巧&#xff0c;让你轻松掌握这一技能。 接口测试…

c语言——输出一个整数的所有因数

//输出一个整数的所有因数 #include<stdio.h> #include<stdlib.h> int main() {int number,i;printf("输入整数&#xff1a;");scanf("%d",&number);printf(" %d 的因数有&#xff1a; ",number);for(i1;i<number;i){if(numb…

java八股文面试[java基础]——String StringBuilder StringBuffer

String类型定义&#xff1a; final String 不可以继承 final char [] 不可以修改 String不可变的好处&#xff1a; hash值只需要算一次&#xff0c;当String作为map的key时&#xff0c; 不需要考虑hash改变 天然的线程安全 知识来源&#xff1a; 【基础】String、StringB…

【C语言】字符串函数的介绍二( strcmp、strncpy、strncat、strncmp)

前言 上篇文章我们介绍了strlen、strcpy、stract这三个函数&#xff0c;接下来我们会学习新的函数&#xff0c;话不多说&#xff0c;让我们直接开始吧 上一篇文章 strcmp 引入&#xff1a; 在进行字符串比较时&#xff0c;不可以直接使用符号&#xff0c; 这是在比较二者的…

LVS-DR模式以及其中ARP问题

目录 LVS_DR LVS_DR数据包流向分析 LVS-DR中ARP问题 问题一 问题二 解决ARP的两个问题的设置方法 LVS-DR特点 LVS-DR优缺点 优点 缺点 LVS-DR集群构建 1.配置负载调度器 2.部署共享存储 3.配置节点服务器 4.测试 LVS 群集 LVS_DR LVS_DR数据包流向分析 客户端…

接口测试,负载测试,并发测试,压力测试区别

接口测试 1.定义&#xff1a;接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是要检查数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及系统间的相互逻辑依赖关系等。 2.目的&#xf…

《C和指针》读书笔记(第十二章 使用结构和指针)

目录 0 简介1 链表2 单链表2.1 在单链表中插入2.1.1 初次尝试2.1.2 优化插入函数2.1.3 在指定位置插入节点&#xff08;补充&#xff09; 2.2 其他链表操作2.2.1 单链表的创建2.2.2 单链表的删除2.2.2.1 删除指定位置的节点2.2.2.2 删除整个链表 3 双链表3.1 在双链表中插入3.1…

需求吞吐效能提升 65%!这家世界500强如何加速业务转型?

昨日&#xff0c;ONES 受邀参加由中关村智联软件服务业质量创新联盟主办的 TiD 2023 质量竞争力大会。会上&#xff0c;ONES 研发效能改进资深咨询顾问董晓红&#xff0c;发表了主题为《解码大型集团企业研发效能提升关键策略》的演讲。 董晓红在研发管理、研发工具链集成、敏捷…

销售管理七要,阿里生存下来的秘诀

企业销售管理“七要”&#xff1a;阿里巴巴生存下来的秘诀 纯纯的干货&#xff0c;有方法有实践 阿里巴巴靠B2B诚信通生存下来的 叫“中供铁军”&#xff0c;很多身影在O2O大战中出现 趣讲大白话&#xff1a;功夫深&#xff0c;铁棒磨成针 【趣讲信息科技260期】 *************…

LVS负载均衡DR(直接路由)模式

在LVS&#xff08;Linux Virtual Server&#xff09;负载均衡中的DR&#xff08;Direct Routing&#xff09;模式下&#xff0c;数据包的流向如下&#xff1a; 客户端发送请求到负载均衡器&#xff08;LVS&#xff09;的虚拟IP&#xff08;VIP&#xff09;。负载均衡器&#x…

SpringBoot | RestTemplate异常处理器ErrorHandler使用详解

关注wx&#xff1a;CodingTechWork 引言 在代码开发过程中&#xff0c;发现很多地方通过RestTemplate调用了第三方接口&#xff0c;而第三方接口需要根据某些状态码或者异常进行重试调用&#xff0c;此时&#xff0c;要么在每个调用的地方进行异常捕获&#xff0c;然后重试&am…

企业文件数据防泄密软件——「天锐绿盾」透明加密保护防泄密管理软件系统

摘要&#xff1a;本文介绍了一款名为「天锐绿盾」的公司文件加密软件&#xff0c;该软件旨在保护公司重要文件的安全性。通过对软件进行详细分析和测试&#xff0c;我们发现「天锐绿盾」具有强大的加密功能、简便的操作界面和高度的兼容性。本文将详细介绍软件的特点、优势及其…

Mysql存储引擎中InnoDB与Myisam的主要区别

在mysql命令窗口中,输入show engins,可以看到mysql的所有引擎,那么这么多的引擎,我们经常使用到的也就两种,MyISAM和InnoDB,这两种引擎究竟有什么区别呢? 1, 事务处理 innodb 支持事务功能,myisam 不支持。 Myisam 的执行速度更快,性能更好。 2,select ,update ,inse…

Shell 编程基础01

0:目录 1.创建新的虚拟机项目 2.linux常见命令和配置时间同步器 3.文件属性 4.if for while和方法 1.创建新的虚拟机项目 默认下一步到虚拟机命名 默认下一步设置磁盘大小 自定义硬件 删除打印机设置映像地址 启动虚拟机 选择 install centOS 7 选择英文 设置时…

[Flash CS6]使用AIR拓展屏幕

虽然目前没多少人使用Flash了&#xff0c;但还是记录一下 一、工具 Adobe Flash CS6 AIR3.2 For Desktop&#xff08;Flash CS6 自带的&#xff09; 二、设置步骤 1.将舞台改为想要拓展的屏幕尺寸大小&#xff08;以下以3840x1080位例子&#xff09; 2.打开AIR 3.2 for Desk…