个人博客传送门
Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便。
产品经理: ***,帮我把数据库中的几个月的数据导成excel
程 序 员: 有什么要求呢?
产品经理: 没有要求只要能使用就可以了
程 序 员: 好的(心里面默默的,“又是一句话的需求”)
。。。。。。
20mins后
。。。。。。
程 序 员: 做好了(自豪感爆棚)
产品经理: 好的,干的漂亮(给你加鸡腿)
点击按钮 loading 。。。
一分钟后 loading 。。。
三分钟后 loading 。。。
五分钟后 还在loading。。。
产品经理: 你这功能不能用呀
程 序 员: ,难道出问题了?
程 序 员: 一顿猛如虎的操作过后,发现数据量太大了OOM
。。。。。。
20mins后
。。。。。。
程 序 员: 突然想到POI在处理的时候数据量太大,试试有什么方法
程 序 员: 一顿操作之后发现EasyExcel
。。。。。。
10mins后
。。。。。。
程 序 员: 替换完POI包之后,重写了方法,然后上线测试,完美的一波。
产品经理: 小伙子不错呀,下班了请你吃个大饼(画大饼)。
上面的情景是不是很熟悉,为了让广大猿猿们都能吃到大饼,我记录下了easyexcel的使用,用作分享和交流。
我们再来看下EasyExcel官方对自己的介绍,EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目,附带上官方已经经过性能测试的数据,可能由于服务器的配置的不同拿到的数据不一致。
64M内存1分钟内读取75M(46W行25列)的Excel
一.首先需要在pom.xml中引入easyexcel的包,如下:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>1.1.2-beta5</version>
</dependency>
二.接下来我编写了一个工具类用来解析和生成excel的类,代码如下。
包含基本的解析和生成文件的方法:
1. 生成文件的方法
EasyExcelUtils.writeExcelOneSheet();
2. 读取文件内容的方法
List<Object> list = EasyExcelUtils.readLessThan1000Row(is);
3. 文件格式的填充/合并等。
这里不去介绍关于样式的问题,有兴趣的话可以去官网了解下,提供了很详细的支持。
https://www.yuque.com/easyexcel/doc/fill
EasyExcelUtils.java 工具类
/**
* 读取少于1000行数据
*
* @param is 文件流
* @return
*/
public static List<Object> readLessThan1000Row(InputStream is) {
return readLessThan1000RowBySheet(is, null);
}
/**
* 导出单个sheet
* @param response
* @param dataList
* @param sheet
* @param fileName
* @throws UnsupportedEncodingException
*/
public static void writeExcelOneSheet(HttpServletResponse response,
List<? extends BaseRowModel> dataList,
Sheet sheet, String fileName) throws UnsupportedEncodingException {
if (CollectionUtils.isEmpty(dataList)) {
return;
}
// 如果sheet为空,则使用默认的
if (null == sheet) {
sheet = initSheet;
}
try {
String value = "attachment; filename=" + new String(
(fileName + ExcelTypeEnum.XLSX.getValue()).getBytes("gb2312"), "ISO8859-1");
response.setContentType("multipart/form-data");
response.setCharacterEncoding("utf-8");
response.setContentType("application/vnd.ms-excel;charset=utf-8");
response.setHeader("Content-disposition", value);
ServletOutputStream out = response.getOutputStream();
ExcelWriter writer = EasyExcelFactory.getWriter(out, ExcelTypeEnum.XLS, true);
// 设置属性类
sheet.setClazz(dataList.get(0).getClass());
writer.write(dataList, sheet);
writer.finish();
out.flush();
} catch (IOException e) {
logger.error("导出失败,失败原因:{}", e);
}
}
三. 接下来我们需要创建一个model用来适配excel的格式,如下:
/**
* @author :Mr.kk
* @date: 2020/3/27 9:26
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ExportModel extends BaseRowModel {
@ExcelProperty(value = "编号", index = 0)
private int num;
@ExcelProperty(value = "姓名", index = 1)
private String name;
@ExcelProperty(value = "年龄", index = 2)
private int age;
}
可以很清楚的看到对于excel的列和model的属性是一一对应的。
四. 接下来需要编写controller进行调用测试了。
/**
* excel的导出
*/
@GetMapping("/exportExcel")
public void exportExcel(HttpServletRequest request, HttpServletResponse response){
String fileName = null;
try {
List<ExportModel> dataList = new ArrayList<>();
for (int i =0 ;i <= 3 ;i ++){
dataList.add(new ExportModel(i,"Mr.kk"+i,18+i));
}
fileName = new String("excel导出".getBytes(), "UTF-8");
EasyExcelUtils.writeExcelOneSheet(response,dataList,null,fileName);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
这里模仿数据库的查询,遍历生成了四条数据用于导出展示,启动工程执行,调用该接口,下载成功,内容如下。
2. 接下来编写excel文件的解析,代码如下:
/**
* excel的导入
*/
@GetMapping("/importExcel")
public Object importExcel(@RequestParam(name = "file",required = true) MultipartFile excl){
if(!excl.isEmpty()){//说明文件不为空
try {
InputStream is = new BufferedInputStream(excl.getInputStream());
List<Object> list = EasyExcelUtils.readLessThan1000Row(is);
//首先是读取行 也就是一行一行读,然后在取到列,遍历行里面的行,根据行得到列的值
for (Object obj: list) {
System.out.println(obj);
}
}catch (Exception e){
e.printStackTrace();
}
}
return "";
}
然后,我们调用接口将上一步生成的文件导入到系统中,打开控制台我们可以看到文件的内容全部被我们打印到了控制台。
五. 总结
***Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便。***
附上代码地址:https://github.com/zhaokuankuan/springboot-excel