最近在工作中遇到一个需求,就是需要在前端实现一个错误模板Excel的下载功能。

实现下载有两种方式,一种是后端生成一个excel,放在服务器指定目录下,然后前端直接去后端拿。第二种是后端传给前端一个json的list,前端用后端传过来的json的list直接在前端合成一个excel。

第一种:后端生成excel

java后端生成excel代码

生成excel工具方法

/** * @author: wu linchun * @creat: 2021-07-29 9:49 * @desc: 将list集合转成Excel文件 * list: 内容list * path: 上传的excel路径 * fileName: 上传的excel名称 **/public static String createExcel(List<? extends Object> list, String path, String fileName) {String result = "";if (list.size() == 0 || list == null) {result = "没有对象信息";} else {Object o = list.get(0);Class<? extends Object> clazz = o.getClass();String className = clazz.getSimpleName();//这里通过反射获取字段数组Field[] fields = clazz.getDeclaredFields();File folder = new File(path);if (!folder.exists()) {folder.mkdirs();}String name = fileName.concat(".xls");WritableWorkbook book = null;File file = null;try {file = new File(path.concat(File.separator).concat(name));//创建xls文件book = jxl.Workbook.createWorkbook(file);WritableSheet sheet = book.createSheet(className, 0);//列int i = 0;//行int j = 0;for (Field f : fields) {j = 0;//这里把字段名称写入excel第一行中Label label = new Label(i, j, f.getName());sheet.addCell(label);j = 1;for (Object obj : list) {Object temp = getFieldValueByName(f.getName(), obj);String strTemp = "";if (temp != null) {strTemp = temp.toString();}//把每个对象此字段的属性写入这一列excel中sheet.addCell(new Label(i, j, strTemp));j++;}i++;}book.write();result = file.getPath();} catch (Exception e) {// TODO Auto-generated catch blockresult = "SystemException";e.printStackTrace();} finally {fileName = null;name = null;folder = null;file = null;if (book != null) {try {book.close();} catch (WriteException e) {// TODO Auto-generated catch blockresult = "WriteException";e.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blockresult = "IOException";e.printStackTrace();}}}}//最后输出文件路径return result;}

<img src=“https://juejin.cn/ “点击并拖拽以移动”” style=“margin: auto” />

下载文件

 /** * @author: wu linchun * @creat: 2021-07-29 13:28 * @desc: 下载错误模板 **/@Overridepublic ResponseEntity<Object> downloadErrorModel() throws FileNotFoundException {// 这里的fileName是指路径+文件名String fileName="move_cms/src/main/resources/static/errorList.xls";File file = new File(fileName);InputStreamResource resource = new InputStreamResource(new FileInputStream((file)));org.springframework.http.HttpHeaders headers = new org.springframework.http.HttpHeaders();headers.add("Content-Disposition", String.format("attachment;filename="%s"", file.getName()));headers.add("Cache-Control", "no-cache,no-store,must-revalidate");headers.add("Pragma", "no-cache");headers.add("Expires", "0");ResponseEntity<Object> responseEntity = ResponseEntity.ok().headers(headers).contentLength(file.length()).contentType(MediaType.parseMediaType("application/text")).body(resource);return responseEntity;}

<img src=“https://juejin.cn/ “点击并拖拽以移动”” style=“margin: auto” />

下载excel的接口

 /** * @author: wu linchun * @creat: 2021-07-29 11:41 * @desc: 下载错误模板 **/@ApiOperation(value = "下载错误模板")@GetMapping(value = "/downloadErrorModel")@PassTokenpublic ResponseEntity<Object> downloadErrorModel() throws FileNotFoundException {System.out.println("下载错误模板");return welfareGrantService.downloadErrorModel();}

<img src=“https://juejin.cn/ “点击并拖拽以移动”” style=“margin: auto” />

在掉/downloadErrorModel这个接口是要注意,只能用超链接 “<a:href />调用,不能使用axios调这个接口。这是由于axios获取的是json

而这个接口返回的是file类型,file会以byte流的形式在http上面传输,因此调/downloadErrorModel这个接口将会接收到byte流,axios默认是接收不了byte的,需要进行一些特殊的设置。可以参考一下这篇:vue使用axios接收流文件_weixin_43869439的博客-CSDN博客

<img src=“https://juejin.cn/ “点击并拖拽以移动”” style=“margin: auto” />

如果使用超链接的方式访问接口进行文件下载的话,则需要获取到后端服务器的ip+port (实际中不建议这么做,因为get请求会暴露ip地址和端口,可通过浏览器f12看到ip地址和端口,不安全)

ip地址可通过 InetAddress.getLocalHost()获取到,端口号直接用@Value从配置文件中拿到。

第二种:前端合成excel

在vue工程中引入两个依赖:file-saver和xlsx

<img src=“https://juejin.cn/ “点击并拖拽以移动”” style=“margin: auto” />

使用“npm install”,安装package.json中新增的依赖

npm install

<img src=“https://juejin.cn/ “点击并拖拽以移动”” style=“margin: auto” />

<img src=“https://juejin.cn/ “点击并拖拽以移动”” style=“margin: auto” />

新增 ExportExcelUtil.js,用来根据list生成excel

/* eslint-disable */
import { saveAs } from 'file-saver'
import XLSX from 'xlsx'function generateArray(table) {var out = [];var rows = table.querySelectorAll('tr');var ranges = [];for (var R = 0; R < rows.length; ++R) {var outRow = [];var row = rows[R];var columns = row.querySelectorAll('td');for (var C = 0; C < columns.length; ++C) {var cell = columns[C];var colspan = cell.getAttribute('colspan');var rowspan = cell.getAttribute('rowspan');var cellValue = cell.innerText;if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue;//Skip rangesranges.forEach(function (range) {if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) {for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null);}});//Handle Row Spanif (rowspan || colspan) {rowspan = rowspan || 1;colspan = colspan || 1;ranges.push({s: {r: R,c: outRow.length},e: {r: R + rowspan - 1,c: outRow.length + colspan - 1}});};//Handle ValueoutRow.push(cellValue !== "" ? cellValue : null);//Handle Colspanif (colspan)for (var k = 0; k < colspan - 1; ++k) outRow.push(null);}out.push(outRow);}return [out, ranges];
};function datenum(v, date1904) {if (date1904) v += 1462;var epoch = Date.parse(v);return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
}function sheet_from_array_of_arrays(data, opts) {var ws = {};var range = {s: {c: 10000000,r: 10000000},e: {c: 0,r: 0}};for (var R = 0; R != data.length; ++R) {for (var C = 0; C != data[R].length; ++C) {if (range.s.r > R) range.s.r = R;if (range.s.c > C) range.s.c = C;if (range.e.r < R) range.e.r = R;if (range.e.c < C) range.e.c = C;var cell = {v: data[R][C]};if (cell.v == null) continue;var cell_ref = XLSX.utils.encode_cell({c: C,r: R});if (typeof cell.v === 'number') cell.t = 'n';else if (typeof cell.v === 'boolean') cell.t = 'b';else if (cell.v instanceof Date) {cell.t = 'n';cell.z = XLSX.SSF._table[14];cell.v = datenum(cell.v);} else cell.t = 's';ws[cell_ref] = cell;}}if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range);return ws;
}function Workbook() {if (!(this instanceof Workbook)) return new Workbook();this.SheetNames = [];this.Sheets = {};
}function s2ab(s) {var buf = new ArrayBuffer(s.length);var view = new Uint8Array(buf);for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;return buf;
}export function export_table_to_excel(id) {var theTable = document.getElementById(id);var oo = generateArray(theTable);var ranges = oo[1];/* original data */var data = oo[0];var ws_name = "SheetJS";var wb = new Workbook(),ws = sheet_from_array_of_arrays(data);/* add ranges to worksheet */// ws['!cols'] = ['apple', 'banan'];ws['!merges'] = ranges;/* add worksheet to workbook */wb.SheetNames.push(ws_name);wb.Sheets[ws_name] = ws;var wbout = XLSX.write(wb, {bookType: 'xlsx',bookSST: false,type: 'binary'});saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), "test.xlsx")
}export function export_json_to_excel({multiHeader = [],header,data,filename,merges = [],autoWidth = true,bookType = 'xlsx'
} = {}) {/* original data */filename = filename || 'excel-list'data = [...data]data.unshift(header);for (let i = multiHeader.length - 1; i > -1; i--) {data.unshift(multiHeader[i])}var ws_name = "SheetJS";var wb = new Workbook(),ws = sheet_from_array_of_arrays(data);if (merges.length > 0) {if (!ws['!merges']) ws['!merges'] = [];merges.forEach(item => {ws['!merges'].push(XLSX.utils.decode_range(item))})}if (autoWidth) {/*设置worksheet每列的最大宽度*/const colWidth = data.map(row => row.map(val => {/*先判断是否为null/undefined*/if (val == null) {return {'wch': 10};}/*再判断是否为中文*/else if (val.toString().charCodeAt(0) > 255) {return {'wch': val.toString().length * 2};} else {return {'wch': val.toString().length};}}))/*以第一行为初始值*/let result = colWidth[0];for (let i = 1; i < colWidth.length; i++) {for (let j = 0; j < colWidth[i].length; j++) {if (result[j]['wch'] < colWidth[i][j]['wch']) {result[j]['wch'] = colWidth[i][j]['wch'];}}}ws['!cols'] = result;}/* add worksheet to workbook */wb.SheetNames.push(ws_name);wb.Sheets[ws_name] = ws;var wbout = XLSX.write(wb, {bookType: bookType,bookSST: false,type: 'binary'});saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), `${filename}.${bookType}`);
}

<img src=“https://juejin.cn/ “点击并拖拽以移动”” style=“margin: auto” />

在.vue中添加下载excel方法

// 下载ExceldownloadExcel () {import('@/utils/ExportExcelUtil').then(excel => {const filterVal = ['item', 'error']const tHeader = ['item', 'error']const data = this.formatModelJson(filterVal, this.errList)console.log(data)console.info(data)excel.export_json_to_excel({header: tHeader,data,filename: 'errorList'})})},// 格式化JSONformatModelJson (filterVal, list) {return list.map(v => filterVal.map(j => {return v[j]}))},

<img src=“https://juejin.cn/ “点击并拖拽以移动”” style=“margin: auto” />

errorList是从后端传过来的

exportExcel () {getErrorListExcel().then(response => {this.errList = response.data})}

<img src=“https://juejin.cn/ “点击并拖拽以移动”” style=“margin: auto” />

使用created方法,在加载.vue时,就调用/getErrorListExcel接口,获取errorList的值。

created () {this.exportExcel()},

<img src=“https://juejin.cn/ “点击并拖拽以移动”” style=“margin: auto” />

调用后端接口的api

import axios from 'axios'export function getErrorListExcel () {return axios.get('http://127.0.0.1:8082/login/getErrorListExcel', {}).then(response => response).catch(error => error)
}

<img src=“https://juejin.cn/ “点击并拖拽以移动”” style=“margin: auto” />

后端接口设置errorList中的值

 @GetMapping("/getErrorListExcel")public List<ErrorItemBO> getErrorListExcel() {List<ErrorItemBO> list = new ArrayList<>();for (int i = 0; i < 10; i++) {ErrorItemBO errorItemBO = new ErrorItemBO();errorItemBO.setItem("item" + i);errorItemBO.setError("error" + i);list.add(errorItemBO);}return list;}

<img src=“https://juejin.cn/ “点击并拖拽以移动”” style=“margin: auto” />

<img src=“https://juejin.cn/ “点击并拖拽以移动”” style=“margin: auto” />

<img src=“https://juejin.cn/ “点击并拖拽以移动”” style=“margin: auto” />

总结

如果涉及到文件下载,尽量后端传一个list,然后都在前端合成相应的文件以到达减轻服务器负担的作用。

最后

最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

Vue中实现自定义excel下载相关推荐

  1. vue中svg转png下载

    vue中svg转png下载 <template><div><button @click="downloadPng">change</but ...

  2. Vue学习笔记:Vue中封装自定义步骤条 实现上下一步

    Vue中封装自定义步骤条 实现上下一步 效果图: 如上图:在VUE中实现效果,VUE+Element,ant都有封装好的UI,直接引用就好了: 这里,觉得样式不符合UI设计,所以自定义封装了一个步骤条 ...

  3. vue导入音乐_【vlog制作】不经电脑,如何在VUE中导入自定义音乐

    VUE按不同风格.节气/节日.每月精选和流行曲集设置了多个音乐库,用户在剪辑视频的时候可以在库中挑选BGM,省掉了找音乐的麻烦,对于新手用户尤为贴心.然而对于频繁使用VUE剪辑视频的用户来说,原配音乐 ...

  4. 「后端小伙伴来学前端了」关于Vue中的自定义事件,组件绑定自定义事件实现通信

    傍晚的月亮 前言 原本这篇打算写Vue中的那个全局事件总线的原理,但是发现自己少写了这个自定义事件,不讲明白这个自定义事件的操作,不好写全局事件原理,于是就有了这篇文章拉. 一.v-on指令 要讲自定 ...

  5. vue中如何进行Excel文件的下载

    文章目录 业务需求: 实现方式 A1.模板下载: A2.搜索下载: A3.勾选下载: A4.上传错误记录下载Excel文件 业务需求: Q1.文件批量导入前,需要按照指定的格式与内容上传Excel文件 ...

  6. vue中使用a标签下载静态资源文件(比如excel、pdf等)后端不参与

    问题描述 平常我们在项目中需要做下载文件的功能,比如下载excel表格.比如下载pdf文件.比如下载word文档,这样的功能,一般是后端做,即:后端返回一个流文件.或者返回一个url地址- 但是,实际 ...

  7. vue中后端做Excel导出功能返回数据流前端如何做处理

    项目中有一个导出功能的实现,用博客来记录一下.因为需求对导出表格的数据格式和样式有要求,所以这个导出功能放到后端来做,而且后端返回的是数据流,所以需要处理成想要的表格并导出来. 先看下效果图: 页面效 ...

  8. vue中通过自定义指令将汉字转化为首字母大写、首字母小写、大写、小写的拼音

    使用情景: 在文本框中输入内容,例如姓名 在页面中将姓名转化为姓名的拼音,包括大写拼音.小写拼音.首字母大写拼音.大写拼音缩写.小写拼音缩写 新建一个 pinyin.js 文件 这是一串又臭又长的un ...

  9. Vue.js + axios 实现excel下载

    在以前实现的下载excel功能中,都是用 <a href="xxx">DOWNLOAD</a> 来实现的. 但是由于项目中采用了token验证,上述的做法就 ...

最新文章

  1. 流程图函数’怎么画_原来函数可以这么美!
  2. 用 Python 爬了点你们喜欢的小电影
  3. 超级干货:3个性能监控和优化命令详解
  4. 在AWS Lambda上运行脚本语言:PHP、Ruby和Go(外文翻译)
  5. Javascript 严格模式详解
  6. python多个分隔符分割字符串_Python中带有多个分隔符的拆分字符串
  7. APAC SharePoint Conference 2007 讲义与资源下载
  8. MySQL安装后默认自带数据库的作用
  9. 数组方法 splice()与slice()的区别
  10. 详细记录基于vue+nodejs+mongodb构建的商城学习(四)基于项目的node.js开发后端的学习与梳理总结...
  11. matlab中的m-file,MATLAB m-file帮助格式化
  12. centos操作系统镜像文件下载
  13. Qt之SQLite数据库可视化工具
  14. OAuth 2.0授权框架详解
  15. js html post提交表单,JS动态创建表单post提交
  16. 公摊面积用计算机怎么计算,公摊面积计算(公摊面积计算器)
  17. 纸牌游戏——小猫钓鱼(队列、栈)
  18. 【微动弹性带方法——续鞍点】
  19. 【uniappAPP实现支付宝授权登录】
  20. PADS如何导入DXF文件

热门文章

  1. 6. FileInputFormat实现类
  2. 如今是云散雪消花残月缺
  3. 架设单位内部FTP服务器
  4. 神经网络、智能芯片、神经计算、飞行控制相关调研
  5. 爬虫学习总结——————血狱魔帝
  6. jQuery如何移除css样式?
  7. halcon脚本-螺丝孔中间小黑圆位置【附源码】
  8. AI绘画发展史(伪):从免费到吃屎;YSDA·自然语言处理课程8K Star;伯克利CS285·深度强化学习课程;前沿论文 | ShowMeAI资讯日报
  9. 详解android framework中StateMachine(HSM层次状态机)的实现
  10. 谷歌浏览器的打印功能