实现Excel的导入、导出
关于excel的操作在工作中经常会遇到,如果只是一次性使用的话,最简单的方式就是通过数据库的可视化工具(如Navicat)查询结果集之后直接一键生成excel了,当然这只能解燃眉之急,并不是长久之计。
首先Excel的导出是比导入简单的,在应用中导出也导出应用的多,导出主要分为前端导出和后端导出。
1. 通过前端方式导出Excel
前提读者你的前端项目是VUE的,如果不是可以看第二个。
- .安装依赖
npm install -S file-saver
npm install -S xlsx
npm install -D script-loader
- 导入Blob.js和Export2Excel.js文件
相当于我们要用的工具类了。
下载地址(https://pan.baidu.com/s/1mmzFl9U0jtQvBK0AjL0urg?pwd=83yc),提取码:83yc
( 笔者已经优化过Export2Excel.js了,之前其他地方下载存在过多列导致报错的问题,这里已经无需考虑了,直接拿来用就好) - 使用方式
将上面所说的js必须放到同一目录下
引入我们的工具类
import { export_json_to_excel2 } from "@/utils/Export2Excel";
在method里面添加两个方法
exportExcel() {require.ensure([], () => {const row = Object.keys(this.tableData[0]).sort().slice(0, -3);const rowc = [].concat(row);row.unshift("序号", "项目号码", "项目名称", "姓名");rowc.unshift("index", "projectCode", "projectName", "userName");const header = row;// 上面设置Excel的表格第一行的标题const filterVal = rowc;const list = this.tableData; //把data里的tableData存到listfor (let i = 0; i < list.length; i++) {list[i]["index"] = i + 1;}var header2 = ["序号","项目号码","项目名称","姓名","项目工作量(原始工作量,人时)每人每天不超过7.5小时",];for (let j = 0; j < row.length; j++) {header2.push("");}const multiHeader = [header2]; // 前一行的表头数据,二维数组,不够的用空白补全const data = this.formatJson(filterVal, list);const merges = ["A1:A2", "B1:B2", "C1:C2", "D1:D2", "E1:Q1"]; // 合并单元格的数据,如何合并参考上面图片讲解export_json_to_excel2({multiHeader,header,merges,data,filename: "工作量核算表",});});},formatJson(filterVal, jsonData) {return jsonData.map((v) => filterVal.map((j) => v[j]));},
准备我们的data数据(这只是笔者提供的例子,可以根据自己的需要去改变)
tableData: [{"2021-09": 0,"2021-10": 75,"2021-11": 7.5,projectCode: "123",projectName: "测试1",userName: "小红",},{"2021-09": 24.5,"2021-10": 62.5,"2021-11": 10.5,projectCode: "123",projectName: "测试1",userName: "小丽",},],
调用我们的方法
//`方法:数据导出`download() {this.exportExcel();},
- 实现效果
2. 通过后端方式导出Excel
为什么会有前端导出和后端导出呢?其实现在的系统很多都是前后端分离的,前端的人无需接触后台也能开发出一个导出功能(笔者是这么想的),后端导出其实就是POI,也是工作中用的比较多的,相对于前端导出,后端导出的安全性要高,处理的效率也比较高,能应用的场景更多,前提你得对POI有一定的了解。
1.引入pom(注:部分功能会因为poi的版本不同而有差异。)
<!-- poi --><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.1.2</version></dependency>
2.实现代码
@SuppressWarnings("resource")@RequestMapping("/exportWorkloads")public void exportWorkloads(HttpServletResponse response) throws Exception {String[] tableHeaders = {"姓名", "工作日期", "工作小时数", "财务小时数", "工作内容"};HSSFWorkbook workbook = new HSSFWorkbook();HSSFSheet sheet = workbook.createSheet("Sheet1");HSSFCellStyle cellStyle = workbook.createCellStyle();cellStyle.setAlignment(HorizontalAlignment.CENTER);cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);Font font = workbook.createFont();font.setBold(true);cellStyle.setFont(font);// 将第一行的五个单元格给合并sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 4));HSSFRow row = sheet.createRow(0);HSSFCell beginCell = row.createCell(0);//第一行的表头String title = "测试测试";beginCell.setCellValue(title);beginCell.setCellStyle(cellStyle);row = sheet.createRow(1);// 创建第二行的表头for (int i = 0; i < tableHeaders.length; i++) {HSSFCell cell = row.createCell(i);cell.setCellValue(tableHeaders[i]);cell.setCellStyle(cellStyle);}//导出的表格数据ArrayList<Map> maps = new ArrayList<>();for (int i = 1; i < 4; i++) {HashMap<String, String> map = new HashMap<>();map.put("姓名","马云"+i);map.put("工作日期","2022-07-0"+i);map.put("工作小时数",String.valueOf(i));map.put("财务小时数",String.valueOf(i));map.put("工作内容","我是第"+i+"天的工作内容");maps.add(map);}for (int i = 0, j = maps.size(); i < j; i++) {//填充数据row = sheet.createRow(i + 2);Map<String,String> map = maps.get(i);row.createCell(0).setCellValue(map.get("姓名"));row.createCell(1).setCellValue(map.get("工作日期"));row.createCell(2).setCellValue(map.get("工作小时数"));row.createCell(3).setCellValue(map.get("财务小时数"));row.createCell(4).setCellValue(map.get("工作内容"));}OutputStream outputStream = response.getOutputStream();response.reset();response.setContentType("application/vnd.ms-excel");String filename = "我是导出的文件名";//文件名要进行编码转换,默认是UTF8可能会显示异常String basename = new String(filename.getBytes("gb2312"), "ISO8859-1");response.setHeader("Content-disposition", "attachment;filename=" + basename + ".xls");workbook.write(outputStream);outputStream.flush();outputStream.close();}
3.实现效果
3. 导入Excel
导入Excel可以理解为从Excel读出数据,笔者使用的工具类来自于与Hutool,后端开发的应该都知道,这是功能强大的工具类了。
1.引入依赖
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.3</version>
</dependency>
2.准备我们的视图数据
3.前端上传文件
附上关键代码(使用什么组件都可以,笔者使用原生的input)
//组件
<input type="file" ref="feedbakcfile" @change="getFile($event)" />//method
getFile(event) {this.file = event.target.files[0];
},
//提交方法exportUp() {if (!this.file) {this.notifyError("请选择文件上传");return;}let formData = new FormData();formData.append("file", this.file);//根据你使用的技术写ajax,这里要注意header!request({url: "/eip/excel/read",method: "post",data: formData,header: { "Content-Type": "multipart/form-data" },}).then((r) => {if (r.success) {this.notifySuccess("导入成功");} else {this.$message.error(r.message);}}).catch((e) => {this.notifyError((e || {}).message || "导入失败");});},
4.代码片段
/*** 导入** @param file* @return* @throws Exception*/@PostMapping("/read")@ResponseBodypublic Map<String, Object> read(MultipartFile file) throws Exception {Map<String, Object> result = new HashMap<>();//首先判断是不是空的文件if (!file.isEmpty()) {//对文文件的全名进行截取然后在后缀名进行删选。int begin = file.getOriginalFilename().indexOf(".");int last = file.getOriginalFilename().length();//获得文件后缀名String a = file.getOriginalFilename().substring(begin, last);if (!(a.endsWith(".xlsx") || a.endsWith(".xls"))) {result.put("success",false);result.put("message","文件类型只能为xlsx、xls!");return result;}} else {result.put("success",false);result.put("message","文件不能为空!");return result;}byte[] byteArr = file.getBytes();InputStream inputStream = new ByteArrayInputStream(byteArr);ExcelReader reader = ExcelUtil.getReader(inputStream, true);//从第3行读起,第一行默认是0List<List<Object>> lists = reader.read(2);if (lists.size() == 0) {result.put("success",false);result.put("message","数据为空。");return result;}//目标数据List<Map> maps = new ArrayList<>();for (int i = 0, j = lists.size(); i < j; i++) {List<Object> data = lists.get(i);HashMap<String, String> map = new HashMap<>();String date = ((DateTime) data.get(0)).toString("yyyy-MM-dd");String name = data.get(1).toString();String plan = data.get(2).toString();String planTask = data.get(3).toString();map.put("date",date);map.put("name",name);map.put("plan",plan);map.put("planTask",planTask);maps.add(map);}//可以打印看看maps是不是你想要的数据result.put("success",true);return result;}