EasyExcel
官方文档
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)
excel转json数据
-
引入easy excel依赖
xml<!-- easy excel --> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.3.2</version> </dependency>
-
编写controller
javapackage 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); } }
-
监听器
javapackage 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<T> implements ReadListener<T> {
public AnalysisEventListener() {
}
public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
this.invokeHeadMap(ConverterUtils.convertToStringMap(headMap, context), context);
}
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
}
}
java
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:所有数据解析完成了 都会来调用,这里可以写保存数据库的逻辑