1. 导入maven依赖
    1. <dependency>
    2. <groupId>com.alibaba</groupId>
    3. <artifactId>easyexcel</artifactId>
    4. <version>2.2.6</version>
    5. </dependency>
    6. <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    7. <dependency>
    8. <groupId>org.projectlombok</groupId>
    9. <artifactId>lombok</artifactId>
    10. <version>1.18.12</version>
    11. <scope>provided</scope>
    12. </dependency>
    1. 定义导出和导入数据需要解析到的对象
    1. @Data
    2. public static class Demo {
    3. @ExcelProperty("数据1")
    4. private String fieldA;
    5. @ExcelProperty("数据2")
    6. private String fieldB;
    7. @ExcelProperty("数据3")
    8. private String fieldC;
    9. @ExcelProperty("数据4")
    10. private String fieldD;
    11. }
    1. 导出excel数据
      使用data()生产需要导出的数据
    1. public List<Demo> data() {
    2. List<Demo> list = new ArrayList<>();
    3. Demo demo = new Demo();
    4. demo.setFieldA("A");
    5. demo.setFieldB("BA1");
    6. demo.setFieldC("CA1");
    7. list.add(demo);
    8. Demo demo1 = new Demo();
    9. demo1.setFieldA("A");
    10. demo1.setFieldB("BA2");
    11. demo1.setFieldC("CA21");
    12. demo1.setFieldD("DA21");
    13. list.add(demo1);
    14. Demo demo2 = new Demo();
    15. demo2.setFieldA("A");
    16. demo2.setFieldB("BA2");
    17. demo2.setFieldC("CA22");
    18. demo2.setFieldD("DA22");
    19. list.add(demo2);
    20. Demo demo3 = new Demo();
    21. demo3.setFieldA("A");
    22. demo3.setFieldB("BA3");
    23. demo3.setFieldC("CA22");
    24. demo3.setFieldD("DA221");
    25. list.add(demo3);
    26. Demo demo4 = new Demo();
    27. demo4.setFieldA("A");
    28. demo4.setFieldB("BA3");
    29. demo4.setFieldC("CA32");
    30. demo4.setFieldD("DA330");
    31. list.add(demo4);
    32. Demo demo5 = new Demo();
    33. demo5.setFieldA("A");
    34. demo5.setFieldB("BA3");
    35. demo5.setFieldC("CA32");
    36. demo5.setFieldD("DA331");
    37. list.add(demo5);
    38. Demo demo6 = new Demo();
    39. demo6.setFieldA("B");
    40. demo6.setFieldB("BB1");
    41. demo6.setFieldC("CB2");
    42. demo6.setFieldD("DB3");
    43. list.add(demo6);
    44. return list;
    45. }
    • 正常导出
      1. @Test
      2. void down() throws FileNotFoundException {
      3. @Cleanup OutputStream os = new FileOutputStream(new File("demo.xlsx"));
      4. EasyExcel.write(os, Demo.class)
      5. .sheet("demo")
      6. .doWrite(data());
      7. }
    • 导出时合并单元格
      自带的单元格合并策略 LoopMergeStrategy , SimpleRowHeightStyleStrategy
      使用方法
      1. @ContentLoopMerge(eachRow =2 ,columnExtend = 1)
      2. @ExcelProperty("数据1")
      3. private String fieldA;


    自定义单元格合并策略,则需实现WriteHandler接口

    1. /**
    2. * 自定义合并策略
    3. */
    4. public class MergeCellStrategy extends AbstractRowWriteHandler {
    5. private final List<ColMark> mark = new ArrayList<>();
    6. private final int totalRow;
    7. public MergeCellStrategy(int totalRow) {
    8. this.totalRow = totalRow;
    9. }
    10. @Override
    11. public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {
    12. if (!isHead) {
    13. final int cellNum = row.getPhysicalNumberOfCells();
    14. // 初始化标记对象
    15. if (CollectionUtils.isEmpty(mark)) {
    16. for (int i = 0; i < cellNum; i++) {
    17. final Cell cell = row.getCell(i);
    18. mark.add(new ColMark(row.getRowNum(), cell.getColumnIndex(), cell.getStringCellValue()));
    19. }
    20. } else {
    21. for (int i = 0; i < cellNum; i++) {
    22. final Cell cell = row.getCell(i);
    23. final ColMark colMark = mark.get(i);
    24. if (Objects.isNull(colMark)) {
    25. mark.set(i, new ColMark(row.getRowNum(), cell.getColumnIndex(), cell.getStringCellValue()));
    26. continue;
    27. }
    28. if (!colMark.getValue().equals(cell.getStringCellValue())) {
    29. // 执行合并
    30. execMerge(writeSheetHolder, row, cellNum, i, false);
    31. // 重置当前col之后的col
    32. resetMarkList(i, cellNum, row.getRowNum(), cell);
    33. }
    34. }
    35. }
    36. // 结束时执行一次合并
    37. if (row.getRowNum() >= totalRow) {
    38. execMerge(writeSheetHolder, row, cellNum, 0, true);
    39. }
    40. }
    41. }
    42. private void execMerge(WriteSheetHolder holder, Row row, int cellNum, int beforeIndex, boolean isAll) {
    43. for (int i = beforeIndex; i < cellNum; i++) {
    44. final ColMark margeMark = mark.get(i);
    45. margeMark.setRowEnd(isAll ? row.getRowNum() : row.getRowNum() - 1);
    46. if (margeMark.rowEnd - margeMark.rowStart >= 1) {
    47. merge(holder, margeMark);
    48. }
    49. }
    50. }
    51. private void merge(WriteSheetHolder holder, ColMark colMark) {
    52. CellRangeAddress cellRangeAddress = new CellRangeAddress(colMark.getRowStart(), colMark.getRowEnd(), colMark.col, colMark.col);
    53. holder.getSheet().addMergedRegionUnsafe(cellRangeAddress);
    54. }
    55. private void resetMarkList(int index, int cellNums, int rowIndex, Cell cell) {
    56. for (int i = index; i < cellNums; i++) {
    57. mark.set(i, null);
    58. }
    59. mark.set(index, new ColMark(rowIndex, cell.getColumnIndex(), cell.getStringCellValue()));
    60. }
    61. }
    62. @RequiredArgsConstructor
    63. @Data
    64. public class ColMark {
    65. @NonNull
    66. private int rowStart;
    67. private int rowEnd;
    68. @NonNull
    69. private int col;
    70. @NonNull
    71. private Object value;
    72. }


    使用方法

    1. @Test
    2. void down() throws FileNotFoundException {
    3. @Cleanup OutputStream os = new FileOutputStream(new File("demo.xlsx"));
    4. EasyExcel.write(os, Demo.class)
    5. .sheet("demo")
    6. .registerWriteHandler(new MergeCellStrategy(data.size()))
    7. .doWrite(data());
    8. }
    • 多sheet导出

      1. @Test
      2. void down1() throws FileNotFoundException {
      3. @Cleanup OutputStream os = new FileOutputStream(new File("demo.xlsx"));
      4. ExcelWriter excelWriter = null;
      5. try {
      6. excelWriter = EasyExcel.write(os).build();
      7. List<DownExcelApi.Demo> data = data();
      8. WriteSheet writeSheet = EasyExcel.writerSheet(0, "sheet1")
      9. .head(DownExcelApi.Demo.class)
      10. .build();
      11. excelWriter.write(data, writeSheet);
      12. WriteSheet writeSheet1 = EasyExcel.writerSheet(1, "sheet2")
      13. .head(DownExcelApi.Demo.class)
      14. .build();
      15. // 分页去数据库查询数据 这里可以去数据库查询每一页的数据
      16. excelWriter.write(data, writeSheet1);
      17. } finally {
      18. if (excelWriter != null) {
      19. excelWriter.finish();
      20. }
      21. }
      22. }

    4 导入excel,并解析数据

    1. @Test
    2. void readExcel() throws FileNotFoundException {
    3. @Cleanup InputStream inputStream = new FileInputStream(new File("*****/demo.xlsx"));
    4. // Excel表格数据记录解析为具体的实体对象集合
    5. final SyncReadListener syncReadListener = new SyncReadListener();
    6. // Excel表格数据记录解析为具体的实体对象集合
    7. EasyExcel.read(inputStream, Demo.class, syncReadListener)
    8. .build()
    9. .read(new ReadSheet(0));
    10. //noinspection rawtypes
    11. List list = syncReadListener.getList();
    12. }

    也可以通过实现ReadListener方法自定以数据处理方法

    注意事项:

    1. 不要使用@Accessors(chain = true)注解