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依赖
<!-- easy excel --><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.3.2</version></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 {// 读取ExcelEasyExcel.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<>();@Overridepublic void invoke(Map<String, Object> data, AnalysisContext context) {//把表头和值放入MapHashMap<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的valueparamsMap.put(key, value);dataList.add(paramsMap);}}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {}@Overridepublic 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) {}
}
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:所有数据解析完成了 都会来调用,这里可以写保存数据库的逻辑