- 导入maven依赖
 
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.6</version></dependency><!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version><scope>provided</scope></dependency>
- 定义导出和导入数据需要解析到的对象
 
@Datapublic static class Demo {@ExcelProperty("数据1")private String fieldA;@ExcelProperty("数据2")private String fieldB;@ExcelProperty("数据3")private String fieldC;@ExcelProperty("数据4")private String fieldD;}
- 导出excel数据
使用data()生产需要导出的数据 
public List<Demo> data() {List<Demo> list = new ArrayList<>();Demo demo = new Demo();demo.setFieldA("A");demo.setFieldB("BA1");demo.setFieldC("CA1");list.add(demo);Demo demo1 = new Demo();demo1.setFieldA("A");demo1.setFieldB("BA2");demo1.setFieldC("CA21");demo1.setFieldD("DA21");list.add(demo1);Demo demo2 = new Demo();demo2.setFieldA("A");demo2.setFieldB("BA2");demo2.setFieldC("CA22");demo2.setFieldD("DA22");list.add(demo2);Demo demo3 = new Demo();demo3.setFieldA("A");demo3.setFieldB("BA3");demo3.setFieldC("CA22");demo3.setFieldD("DA221");list.add(demo3);Demo demo4 = new Demo();demo4.setFieldA("A");demo4.setFieldB("BA3");demo4.setFieldC("CA32");demo4.setFieldD("DA330");list.add(demo4);Demo demo5 = new Demo();demo5.setFieldA("A");demo5.setFieldB("BA3");demo5.setFieldC("CA32");demo5.setFieldD("DA331");list.add(demo5);Demo demo6 = new Demo();demo6.setFieldA("B");demo6.setFieldB("BB1");demo6.setFieldC("CB2");demo6.setFieldD("DB3");list.add(demo6);return list;}
- 正常导出
@Testvoid down() throws FileNotFoundException {@Cleanup OutputStream os = new FileOutputStream(new File("demo.xlsx"));EasyExcel.write(os, Demo.class).sheet("demo").doWrite(data());}
 
- 导出时合并单元格
自带的单元格合并策略 LoopMergeStrategy , SimpleRowHeightStyleStrategy
使用方法@ContentLoopMerge(eachRow =2 ,columnExtend = 1)@ExcelProperty("数据1")private String fieldA;
 
自定义单元格合并策略,则需实现WriteHandler接口
/*** 自定义合并策略*/public class MergeCellStrategy extends AbstractRowWriteHandler {private final List<ColMark> mark = new ArrayList<>();private final int totalRow;public MergeCellStrategy(int totalRow) {this.totalRow = totalRow;}@Overridepublic void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {if (!isHead) {final int cellNum = row.getPhysicalNumberOfCells();// 初始化标记对象if (CollectionUtils.isEmpty(mark)) {for (int i = 0; i < cellNum; i++) {final Cell cell = row.getCell(i);mark.add(new ColMark(row.getRowNum(), cell.getColumnIndex(), cell.getStringCellValue()));}} else {for (int i = 0; i < cellNum; i++) {final Cell cell = row.getCell(i);final ColMark colMark = mark.get(i);if (Objects.isNull(colMark)) {mark.set(i, new ColMark(row.getRowNum(), cell.getColumnIndex(), cell.getStringCellValue()));continue;}if (!colMark.getValue().equals(cell.getStringCellValue())) {// 执行合并execMerge(writeSheetHolder, row, cellNum, i, false);// 重置当前col之后的colresetMarkList(i, cellNum, row.getRowNum(), cell);}}}// 结束时执行一次合并if (row.getRowNum() >= totalRow) {execMerge(writeSheetHolder, row, cellNum, 0, true);}}}private void execMerge(WriteSheetHolder holder, Row row, int cellNum, int beforeIndex, boolean isAll) {for (int i = beforeIndex; i < cellNum; i++) {final ColMark margeMark = mark.get(i);margeMark.setRowEnd(isAll ? row.getRowNum() : row.getRowNum() - 1);if (margeMark.rowEnd - margeMark.rowStart >= 1) {merge(holder, margeMark);}}}private void merge(WriteSheetHolder holder, ColMark colMark) {CellRangeAddress cellRangeAddress = new CellRangeAddress(colMark.getRowStart(), colMark.getRowEnd(), colMark.col, colMark.col);holder.getSheet().addMergedRegionUnsafe(cellRangeAddress);}private void resetMarkList(int index, int cellNums, int rowIndex, Cell cell) {for (int i = index; i < cellNums; i++) {mark.set(i, null);}mark.set(index, new ColMark(rowIndex, cell.getColumnIndex(), cell.getStringCellValue()));}}@RequiredArgsConstructor@Datapublic class ColMark {@NonNullprivate int rowStart;private int rowEnd;@NonNullprivate int col;@NonNullprivate Object value;}
使用方法
@Testvoid down() throws FileNotFoundException {@Cleanup OutputStream os = new FileOutputStream(new File("demo.xlsx"));EasyExcel.write(os, Demo.class).sheet("demo").registerWriteHandler(new MergeCellStrategy(data.size())).doWrite(data());}
多sheet导出
@Testvoid down1() throws FileNotFoundException {@Cleanup OutputStream os = new FileOutputStream(new File("demo.xlsx"));ExcelWriter excelWriter = null;try {excelWriter = EasyExcel.write(os).build();List<DownExcelApi.Demo> data = data();WriteSheet writeSheet = EasyExcel.writerSheet(0, "sheet1").head(DownExcelApi.Demo.class).build();excelWriter.write(data, writeSheet);WriteSheet writeSheet1 = EasyExcel.writerSheet(1, "sheet2").head(DownExcelApi.Demo.class).build();// 分页去数据库查询数据 这里可以去数据库查询每一页的数据excelWriter.write(data, writeSheet1);} finally {if (excelWriter != null) {excelWriter.finish();}}}
4 导入excel,并解析数据
@Testvoid readExcel() throws FileNotFoundException {@Cleanup InputStream inputStream = new FileInputStream(new File("*****/demo.xlsx"));// Excel表格数据记录解析为具体的实体对象集合final SyncReadListener syncReadListener = new SyncReadListener();// Excel表格数据记录解析为具体的实体对象集合EasyExcel.read(inputStream, Demo.class, syncReadListener).build().read(new ReadSheet(0));//noinspection rawtypesList list = syncReadListener.getList();}
也可以通过实现ReadListener方法自定以数据处理方法
注意事项:
