EasyExcel官方文档 - 基于Java的Excel处理工具 | Easy Excel (alibaba.com)
Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。一旦并发上来后一定会OOM或者JVM频繁的full gc.
easyexcel重写了poi对07版Excel的解析,一个3M的excel用POI sax解析依然需要100M左右内存,改用easyexcel可以降低到几M,并且再大的excel也不会出现内存溢出;03版依赖POI的sax模式,在上层做了模型转换的封装,让使用者更加简单方便。
关于Easyexcel | Easy Excel (alibaba.com)
引入easy excel依赖
<dependency>
<groupId>com.alibabagroupId>
<artifactId>easyexcelartifactId>
<version>3.3.2version>
dependency>
编写controller
package com.junfeng.tool.controller;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.junfeng.tool.config.EasyExcelListener;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/***
* @Author junfeng
*/
@Api(tags = "excel")
@ApiSupport(author = "1033110136@qq.com", order = 1)
@RestController
@RequestMapping("/api/excel")
@Slf4j
public class ExcelController {
@ApiOperationSupport(author = "junfeng")
@ApiOperation(value = "excel转换json")
@PostMapping("/upload")
public Object upload(@RequestParam("file") MultipartFile file) throws IOException {
// 读取Excel
EasyExcel.read(file.getInputStream(), new EasyExcelListener()).sheet().headRowNumber(1).doRead();
// 从监听中获取结果集
List<Map<String, Object>> importList = EasyExcelListener.dataList;
log.info("导入集合 list = {}", JSON.toJSON(importList));
return JSON.toJSON(importList);
}
}
监听器
package com.junfeng.tool.config;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
public class EasyExcelListener extends AnalysisEventListener<Map<String, Object>> {
private Map<Integer, String> headMap;
public static final List<Map<String, Object>> dataList = new ArrayList<>();
@Override
public void invoke(Map<String, Object> data, AnalysisContext context) {
//把表头和值放入Map
HashMap<String, Object> paramsMap = new HashMap<>();
for (int i = 0; i < data.size(); i++) {
String key = headMap.get(i);
Object value = data.get(i);
//将表头作为map的key,每行每个单元格的数据作为map的value
paramsMap.put(key, value);
dataList.add(paramsMap);
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
}
@Override
public void invokeHeadMap(Map<Integer, String> head, AnalysisContext context) {
headMap = head;
}
}
public abstract class AnalysisEventListener implements ReadListener {
public AnalysisEventListener() {
}
public void invokeHead(Map> headMap, AnalysisContext context) {
this.invokeHeadMap(ConverterUtils.convertToStringMap(headMap, context), context);
}
public void invokeHeadMap(Map headMap, AnalysisContext context) {
}
}
public interface ReadListener<T> extends Listener {
default void onException(Exception exception, AnalysisContext context) throws Exception {
throw exception;
}
default void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
}
void invoke(T var1, AnalysisContext var2);
default void extra(CellExtra extra, AnalysisContext context) {
}
void doAfterAllAnalysed(AnalysisContext var1);
default boolean hasNext(AnalysisContext context) {
return true;
}
}
如下图EasyExcelListener继承AnalysisEventListener实现接口ReadListener

ReadListener中有三个重要接口
invokeHead:解析标题头的数据
invoke:这个每一条数据解析都会来调用,这里可以将数据存到list集合里面,给外部调用。
doAfterAllAnalysed:所有数据解析完成了 都会来调用,这里可以写保存数据库的逻辑