前端下载Excel时 URL.createObjectURL报错问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端下载Excel时 URL.createObjectURL报错问题相关的知识,希望对你有一定的参考价值。

参考技术A 首先前端用的是vue环境,用axios独立封装的一个接口,请求接口开始是这样的

前端请求后,获取到数据

然后浏览器会报一个错误 Failed to execute 'createObjectURL' on 'URL': No function was found that matched the signature provided.

查阅资料后得知 当 URL.createObjectURL(data) 这个data不是 blob类型就会报错

只要在axios请求接口中加一个参数 responseType: 'blob' 就能解决 导出报错问题

Excel 模板下载功能 + 前后端解析 Excel 文件代码封装 + 前端上传 Excel 至数据库(SpringBoot + Vue 版)

最近做需求时遇到一个可向导的文件上传功能,现在做完了来分享下,基本能满足大伙80%的需求了

一、Excel 模板下载功能

后端代码(这是07版的Excel,需要03版的修改 XSSFWorkbook workbook = new XSSFWorkbook(fis); 这行代码即可):

public void download(HttpServletResponse response) throws IOException 
   FileInputStream fis = new FileInputStream("文件路径");
   ServletOutputStream out = null;
   try 
       XSSFWorkbook workbook = new XSSFWorkbook(fis);
       response.setContentType("application/binary;charset=ISO8859-1");
       String fileName = java.net.URLEncoder.encode("模板文件名字", "UTF-8");
       response.setHeader("Content-disposition", "attachment; filename=" + fileName + ".xlsx");
       out = response.getOutputStream();
       workbook.write(out);
       out.flush();
       out.close();
    catch (IOException e) 
       e.printStackTrace();
    finally 
       //关闭文件输出流
       fis.close();
   
   return;

前端代码:

main.js:
	引入跨域请求依赖axios
	import axios from 'axios'
	挂载axios
	Vue.prototype.$http = axios
	设置访问根路径
	axios.defaults.baseURL = "http://localhost:端口号看后端"

JS代码:
	downloadFile() 
	    this.$http(
	        method: "get",
	        headers: 
	        "content-type": "application/json", // 默认值
	        Authorization: "Bearer " + sessionStorage.getItem("access_token"),
	        ,
	        url: '后端接口地址',
	        params: 'name':'Jack',
	        responseType: "blob",
	    ).then(function (res) 
	        let blob = new Blob([res.data]); //  type: "application/vnd.ms-excel" 
	        let url = window.URL.createObjectURL(blob); // 创建一个临时的url指向blob对象
	        // 创建url之后可以模拟对此文件对象的一系列操作,例如:预览、下载
	        let a = document.createElement("a");
	        a.href = url;
	        a.download = "上传模板.xlsx";
	        a.click();
	        // 释放这个临时的对象url
	        window.URL.revokeObjectURL(url);
	    ).catch(function (res) 
	        console.log("error", res);
	    );
	

二、前端解析 Excel 并展示在页面的功能(需要去下载xlsx 依赖)

Html:

按钮部分:
	<el-upload action accept=".xlsx, .xls" :auto-upload="false" :show-file-list="false" :on-change="handle">
	   <el-button slot="trigger" type="primary">选取EXCEL文件</el-button>
	</el-upload>
数据展示部分:
	<div v-show="show">
	    <el-table :data="dataList" stripe style="width:100%" :height="height" border>
	        <el-table-column type="index" width="50" align="center"></el-table-column>
	        <el-table-column prop="按需填写" label="按需填写" width="180" align="center"></el-table-column>
	        <el-table-column prop="按需填写" label="按需填写" width="100" align="center"></el-table-column>
	        <el-table-column prop="按需填写" label="按需填写" width="180" align="center"></el-table-column>
	        <el-table-column prop="按需填写" label="按需填写" width="90" align="center"></el-table-column>
	        <el-table-column prop="按需填写" label="按需填写" align="center" width="120"></el-table-column>
	        <el-table-column prop="按需填写" label="按需填写" align="center" width="100"></el-table-column>
	    </el-table>
	</div>	

JS:

data()
    return 
        dataList: [],
        show: false
    
,
methods: 
	async handle(ev) 
	    let file = ev.raw; // 获取上传的文件
	    if(!file) return;
	    // 隐藏表格
	    this.show = false;
	    // 读取文件中的数据
	    let data = await readFile(file);
	    // workbook:创建一个EXCEL表,并读取二进制数据,worksheet:默认拿第一张表的数据
	    let workbook = xlsx.read(data,type:'binary'), worksheet = workbook.Sheets[workbook.SheetNames[0]];
	    // 数据转JSON格式 
	    data = xlsx.utils.sheet_to_json(worksheet);
	    // 把读取出来的数据变为对应后端的字段
	    let arr = [];
	    data.forEach(item => 
	        let obj = ;
	        for(let key in character)
	            if(!character.hasOwnProperty(key)) break;
	            let v = character[key], text = v.text, type = v.type;
	            v = item[text] || "";
	            type === "string" ? (v = String(v)) : null;
	            type === "number" ? (v = Number(v)) : null;
	            obj[key] = v;
	        
	        arr.push(obj);
	    );
	    // 解析完毕后展示数据
	    this.show = true;
	    this.dataList = arr;
	,
	

三、前端上传 Excel 至数据库

后续就给核心实现代码了

// 将数据一条一条传给后端
let n = 0;
let send = async () => 
    if(n > this.dataList.length - 1)
        this.$message(
            message: "亲,文件已经上传完毕!",
            type: 'success',
            showClose: true
        );
        this.show = false;
        return;
     
    let body =  this.dataList[n];
    const data:res = await this.$http.post("后端接口地址",body);
    if(res=="success")
        n++;
    
    send();
;
send();

四、后端读取 Excel 工具类( POI,较为复杂且会 OOM,建议使用下一种)

/* 封装一个读取文件的工具类 */
public void read(FileInputStream inputStream) throws Exception
   // 1、创建工作簿
   Workbook workbook = new XSSFWorkbook(inputStream);
   // 2、获取表
   Sheet sheet = workbook.getSheetAt(0);
   // 3、获取数据
   int rowCount = sheet.getPhysicalNumberOfRows();
   for(int rowNum = 1; rowNum < rowCount; rowNum++)
       Row rowData = sheet.getRow(rowNum);
       if(rowData != null)
           //获得该行的列的数目
           int lineCount = rowData.getPhysicalNumberOfCells();
           for(int lineNum = 0; lineNum < lineCount ;lineNum++)
               System.out.print("第" + rowNum +"行,第" + lineNum +"列:");
               Cell cell = rowData.getCell(lineNum);
               //判断数据类型
               if(cell != null)
                   CellType cellType = cell.getCellTypeEnum();
                   switch (cellType)
                       case STRING:
                           System.out.println("字符串:" + cell.getStringCellValue()); break;
                       case BOOLEAN:
                           System.out.println("布尔:" + cell.getBooleanCellValue());  break;
                       case BLANK:
                           System.out.println("空"); break;
                       case ERROR:
                           System.out.println("没有该数据类型"); break;
                       case NUMERIC:
                           //如果是日期就直接输出,否则就装换为String,然后输出
                           if(HSSFDateUtil.isCellDateFormatted(cell))
                               System.out.println("时间:"+new DateTime(cell.getDateCellValue()).toString("yyyy-MM-dd"));
                           else
                               cell.setCellType(CellType.STRING);
                               System.out.println("整型:" + cell.toString()); break;
                           
                       default:
                           System.out.println("其他位置没有数据");break;
                   
               
           
       
   
   inputStream.close();

五、后端读取 Excel 工具类(ExsyExcel,还是阿里的香)

一句话就搞定了,香一匹好吧!(读取的数据以对象的形式放在 List 中,并返回给你!)

public <T> List<T> syncReadModel(InputStream file, Class clazz)
   	return EasyExcelFactory.read(file).sheet(0).head(clazz).doReadSync();

以上是关于前端下载Excel时 URL.createObjectURL报错问题的主要内容,如果未能解决你的问题,请参考以下文章

Excel 模板下载功能 + 前后端解析 Excel 文件代码封装 + 前端上传 Excel 至数据库(SpringBoot + Vue 版)

Excel 模板下载功能 + 前后端解析 Excel 文件代码封装 + 前端上传 Excel 至数据库(SpringBoot + Vue 版)

前端axios下载excel

前端下载excel文件功能的三种方法

数据使用Excel导出下载

00006-java 下载一个excel模板(文件),前端layui按钮