前言
- 将表格信息导出为Excel表格(导出数)
- 将Excel表格信息录入到数据库(导入数据)
操作Excel目前比较流行的就是 Apache POI 和阿里巴巴的 EasyExcel
Apache POI
Apache POI 官网:https://poi.apache.org/
- HSSF:Excel97-2003版本,扩展名为.xls。一个sheet最大行数65536,最大列数256。
- XSSF:Excel2007版本开始,扩展名为.xlsx。一个sheet最大行数1048576,最大列数16384。
- SXSSF:是在XSSF基础上,POI3.8版本开始提供的支持低内存占用的操作方式,扩展名为.xlsx。
Excel版本兼容性是向下兼容。
03版本和07版的Excel表的生成
java
<!--xls(03版本)-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.9</version>
</dependency>
<!--xlsx(07版本)-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.9</version>
</dependency>
代码
java
@Override
@CrossOrigin
public void testEasyExcel(Map<String, Object> map, HttpServletResponse response) throws IOException {
// var sheetName = "工作表名"
// var headList = ["表头1", "表头2"]
// var filedList = ["字段名1", "字段名2"]
// var dataList = [{字段名1: "2914"}, {字段名2: "2935"}, {字段名3: "2937"}]
String sheetName = map.get("sheetName").toString();
List<String> headList = (List)map.get("headList");
List<String> filedList = (List)map.get("filedList");
List<Map> dataList = (List)map.get("dataList");
// 创建一个03版本的工作簿
Workbook workbook = new HSSFWorkbook();
// 创建一个07版本的工作簿
// Workbook workbook = new XSSFWorkbook();
//
// Workbook workbook = new SXSSFWorkbook();
// 创建一个工作表,指定表名
Sheet sheet = workbook.createSheet(sheetName);
// 创建一个行
Row row = sheet.createRow(0);
// 设置行高
row.setHeight((short)450);
// 设置样式
HSSFCellStyle cellStyle = (HSSFCellStyle)workbook.createCellStyle();
// XSSFCellStyle cellStyle = (XSSFCellStyle) workbook.createCellStyle();
// 设置背景颜色
cellStyle.setFillBackgroundColor(IndexedColors.SEA_GREEN.getIndex());
// 设置居中
// cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
// 设置字体
HSSFFont font = (HSSFFont)workbook.createFont();
// XSSFFont font = (XSSFFont)workbook.createFont();
font.setFontName("宋体");
font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
font.setFontHeightInPoints((short)12);
cellStyle.setFont(font);
// 写入表头
for (int i = 0; i < headList.size(); i++) {
row.createCell(i).setCellValue(headList.get(i));
row.getCell(i).setCellStyle(cellStyle);
}
// 写入字段名和写入数据
for (int i = 0; i < dataList.size(); i++) {
row = sheet.createRow(i + 1);
row.setHeight((short)450);
Map<String, String> datamap = dataList.get(i);
for (int j = 0; j < filedList.size(); j++) {
String value = String.valueOf(datamap.get(filedList.get(j)));
if (value != null && !"null".equals(value)) {
row.createCell(j).setCellValue(value);
}
}
}
// 文件扩展名
response.setContentType("application/vnd.ms-excel;charset=utf-8");
OutputStream os = response.getOutputStream();
// 输出
workbook.write(os);
// 刷新
os.flush();
// 关闭
os.close();
// 清除临时文件
// ((SXSSFWorkbook)workbook).dispose();
}
03版本和07版的Excel表的读取
java
@Override
@CrossOrigin
public void testEasyExcel(Map<String, Object> map, HttpServletResponse response) throws IOException {
// 获取文件流 03 xls 07 xlsx
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Desktop\\工号批量导入模板.xls");
// 读取excel
Workbook workbook = new HSSFWorkbook(fileInputStream);
// 拿到工作表
Sheet sheet = workbook.getSheetAt(0);
// 获取标题行内容
Row rowTitle = sheet.getRow(1);
if (rowTitle != null) {
// 获取这行有多少列
int cellCount = rowTitle.getPhysicalNumberOfCells();
// 循环得到这一行的所有数据
for (int cellNum = 0; cellNum < cellCount; cellNum++) {
Cell cell = rowTitle.getCell(cellNum);
if (cell != null) {
int cellType = cell.getCellType();
// 这里标题行数据的类型全部为字符串
String stringCellValue = cell.getStringCellValue();
System.out.print(stringCellValue + " | ");
}
}
System.out.println();
}
// 获取表中的内容,即获取除了第一行的内容,取表中总共有多少行
int physicalNumberOfRows = sheet.getPhysicalNumberOfRows();
// 从第二行开始循环,即获取除了第一行的内容
for (int rowNum = 2; rowNum < physicalNumberOfRows; rowNum++) {
Row rowData = sheet.getRow(rowNum);
if (rowData != null) {
// 根据标题行获取多少列
int cellCount = rowTitle.getPhysicalNumberOfCells();
// 循环得到这一行的所有数据
for (int cellNum = 0; cellNum < cellCount; cellNum++) {
Cell cell = rowData.getCell(cellNum);
if (cell != null) {
int cellType = cell.getCellType();
String cellValue = "";
// 匹配列的数据类型
switch (cellType) {
// 字符串
case HSSFCell.CELL_TYPE_STRING:
cellValue = cell.getStringCellValue();
break;
// 布尔值
case HSSFCell.CELL_TYPE_BOOLEAN:
cellValue = String.valueOf(cell.getBooleanCellValue());
break;
// 空
case HSSFCell.CELL_TYPE_BLANK:
break;
// 数字(数字又分为日期和普通数字)
case HSSFCell.CELL_TYPE_NUMERIC:
// 如果为日期
if (HSSFDateUtil.isCellDateFormatted(cell)) {
Date date = cell.getDateCellValue();
cellValue = new DateTime(date).toString("yyyy-MM-dd");
} else {
// 不是日期格式的话,需要防止数字过长,转换为字符串输出
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
cellValue = cell.toString();
}
break;
// 错误的数据类型
case HSSFCell.CELL_TYPE_ERROR:
break;
}
System.out.print(cellValue + " | ");
}
}
System.out.println();
}
}
fileInputStream.close();
}
通过 Blob 下载文件
前端的各种后台管理系统中,往往都会存在大量数据的展示,分析等,一般这种项目都会有数据导出功能,在开发中,一般都是后端返回Blob数据类型,也就是一个二进制对象,那么本篇文章就是讲解前端拿到Blob数据后该怎么处理。
这里简单说一下Blob,全称Binary large Object,二进制大对象(BLOB)是一种可以存储二进制对象或数据的数据类型。
前端中Blob对象的构造函数语法:
java
new Blob(array, options)
参数 array 是一个数据序列即数组,可以是任意格式的值,例如,任意数量的字符串,Blobs 以及 ArrayBuffers。
参数 options 用于指定将要放入Blob中的数据的类型(MIME)
- 在封装请求的时候一定要记得加上responseType。
java
/**
* 导出exportExcel
* @param data
*/
public static exportExcel(data) {
return axios({
url: ``,
method: 'get',
params: data,
responseType: "blob"//定义好返回的数据类型
});
}
- 拿到Blob数据类型转化为文件并下载。
java
/**
* 导出文件下载方法
* @param data 这个参数就是从接口返回的Blob二进制文件流
*/
const exportFile= (data) => {
const blob = new Blob([data], {type: "application/vnd.ms-excel;charset=utf-8"});
const fileName = "文件名" + new Date().getTime() + ".xls";//我这里是文件名加上时间,可以根据自己需求来
const elink = document.createElement("a"); // 创建a标签
elink.download = fileName; // 为a标签添加download属性 //命名下载名称
elink.style.display = "none";
elink.href = URL.createObjectURL(blob);
document.body.appendChild(elink);
elink.click(); // 点击下载
URL.revokeObjectURL(elink.href); // 释放URL 对象
document.body.removeChild(elink); // 释放标签
}
EasyExcel
easyExcel 官网:https://easyexcel.opensource.alibaba.com/
EasyExcel 是阿里巴巴开源的一个excel处理框架、以使用简单、节省内存著称,EasyExcel 能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析。
下图是EasyExcel和POI在解析Excel时的对比图

代码
java
@Override
@CrossOrigin
public void testEasyExcel(Map<String, Object> map, HttpServletResponse response) throws IOException {
String fileName = "C:\\Users\\13992\\Desktop\\EasyTest.xlsx";
// 这里需要指定写用哪个class去写,然后写到第一个sheet,名字为模板然后文件流会自动关闭
// 如果这里想使用03 则 传入excelType参数即可
List<Map> list = (List<Map>) map.get("dataList");
List<DemoData> demoList = ListUtils.newArrayList();
for(int i=0;i<list.size();i++){
DemoData data = new DemoData();
data.setStaffCode(list.get(i).get("staffCode").toString());
data.setStaffName(list.get(i).get("staffName").toString());
demoList.add(data);
}
EasyExcel.write(fileName, DemoData.class).sheet(map.get("sheetName").toString())// 工作表名
.doWrite(demoList);
}
结论
POI存在的问题:非常的消耗内存,EasyExcel 遇到再大的excel都不会出现内存溢出的问题,能够将一个原本3M的excel文件,POI来操作将会占用内存100M,使用EasyExcel降低到几KB,使用起来更加简单。而easyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析。