前端下载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 版)