一 概述
EasyExcel是一个基于Java的简单,省内存的读写Excel的开源项目。在尽可能节省内存的情况下支持读写百M的Excel。
文档地址:EasyExcel
Github地址:https://github.com/alibaba/easyexcel
64M内存1分钟内读取75M(46W行25列)的Excel
当然还有急速模式能更快,但是内存占用会在100M多一点
二 实现Excel文件上传并读取指定列的数据
pom
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.0.0</version>
</dependency>
<!--<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.11</version>
</dependency>-->
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.0.0</version>
</dependency>
<!-- <dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>3.11</version>
</dependency>-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<!--poi end-->
<!--alibaba easyExcel start-->
<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.10</version>
</dependency>
监听器
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qskj.print.printcommon.entity.PrintLoanEntity;
import com.qskj.print.printcommon.exception.CommonException;
import com.qskj.print.printcommon.mapper.PrintLoanMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
@Slf4j
public class ExcelDataListener extends AnalysisEventListener<ExcelColumn> {
/**
* 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
*/
private static final int BATCH_COUNT = 5;
List<ExcelColumn> excelDataList = new ArrayList<>();
/**
* 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没 用。
*/
private DemoDAO demoDAO;
public ExcelDataListener() {
// 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
demoDAO = new DemoDAO();
}
/**
* 这个每一条数据解析都会来调用
*
* @param excelColumn
* @param analysisContext
**/
@Override
public void invoke(ExcelColumn excelColumn, AnalysisContext analysisContext) {
excelDataList.add(excelColumn);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
list.clear();
}
}
/**
* 所有数据解析完成了 都会来调用
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
LOGGER.info("所有数据解析完成!");
}
/**
* 加上存储数据库
*/
private void saveData() {
LOGGER.info("{}条数据,开始存储数据库!", list.size());
demoDAO.save(list);
LOGGER.info("存储数据库成功!");
}
}
if (excelDataList.size() >= BATCH_COUNT) {
updateLoanData();
//存储完清理list
excelDataList.clear();
}
}
/**
* 所有数据解析完成了 都会来调用
*
* @param analysisContext
*/
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
updateLoanData();
}
/**
* 更新数据
*/
private void updateLoanData() {
log.info("更新数据方法!",);
}
}
指定列的下标或者列名
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
public class ExcelColumn implements Serializable {
private static final long serialVersionUID = -5176115674290246277L;
@ExcelProperty(index = 0)
private String columnOne;
@ExcelProperty(index = 8)
private String columnEight;
@ExcelProperty(index = 9)
private String columnNine;
}
service方法
@Override
public String importExcel(MultipartFile file) {
String suffixExpect = "xlsx,xls";
String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1);
if (!suffixExpect.contains(suffix)) {
throw new CommonException("请上传Excel文件,支持XLSX,XLS格式~");
}
try {
EasyExcel.read(file.getInputStream(), ExcelColumn.class, new ExcelDataListener(/*Spring注入的实例*/)).sheet().doRead();
} catch (IOException e) {
e.printStackTrace();
}
return "success";
}
Controller方法
@RequestMapping(value = "/supplierOrder/importExcel", method = RequestMethod.POST)
public String InputExcel(@RequestParam("file") MultipartFile file) {
return orderService.importExcel(file);
}