easyexcel 版本:3.0.5
    自定义单元格合并WriterHandler

    1. import com.alibaba.excel.metadata.Head;
    2. import com.alibaba.excel.write.handler.CellWriteHandler;
    3. import com.alibaba.excel.write.merge.AbstractMergeStrategy;
    4. import org.apache.commons.collections4.CollectionUtils;
    5. import org.apache.poi.ss.usermodel.Cell;
    6. import org.apache.poi.ss.usermodel.CellType;
    7. import org.apache.poi.ss.usermodel.Row;
    8. import org.apache.poi.ss.usermodel.Sheet;
    9. import org.apache.poi.ss.util.CellRangeAddress;
    10. import java.util.HashSet;
    11. import java.util.List;
    12. import java.util.Objects;
    13. import java.util.Set;
    14. /**
    15. * @author mori
    16. * @date 2022/3/9
    17. */
    18. public class CellMergeWriterHandler {
    19. public static CellWriteHandler getCellMergeWriterHandler(CellMergeEnum cellMergeEnum) {
    20. if (CellMergeEnum.ROW.equals(cellMergeEnum)) {
    21. return new RowMergeWriterHandler();
    22. }
    23. if (CellMergeEnum.COLUMN.equals(cellMergeEnum)) {
    24. return new ColumnMergeWriterHandler();
    25. }
    26. return null;
    27. }
    28. public static CellWriteHandler getRowMergeWriterHandler(List<Integer> rows) {
    29. return getCellWriteHandler(CellMergeEnum.ROW, rows);
    30. }
    31. public static CellWriteHandler getColumnMergeWriterHandler(List<Integer> cols) {
    32. return getCellWriteHandler(CellMergeEnum.COLUMN, cols);
    33. }
    34. public static CellWriteHandler getCellWriteHandler(CellMergeEnum cellMergeEnum, List<Integer> columnsOrRows) {
    35. if (CellMergeEnum.ROW.equals(cellMergeEnum)) {
    36. return new RowMergeWriterHandler(new HashSet<>(columnsOrRows));
    37. }
    38. if (CellMergeEnum.COLUMN.equals(cellMergeEnum)) {
    39. return new ColumnMergeWriterHandler(new HashSet<>(columnsOrRows));
    40. }
    41. return null;
    42. }
    43. public static class ColumnMergeWriterHandler extends AbstractMergeStrategy {
    44. private Set<Integer> mergeCols;
    45. public ColumnMergeWriterHandler() {
    46. }
    47. public ColumnMergeWriterHandler(Set<Integer> mergeCols) {
    48. this.mergeCols = mergeCols;
    49. }
    50. @Override
    51. protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
    52. if (CollectionUtils.isNotEmpty(this.mergeCols) && !this.mergeCols.contains(cell.getColumnIndex())) {
    53. return;
    54. }
    55. mergeCell(cell.getSheet(), cell, CellMergeEnum.COLUMN);
    56. }
    57. }
    58. public static class RowMergeWriterHandler extends AbstractMergeStrategy {
    59. private Set<Integer> mergeCols;
    60. public RowMergeWriterHandler() {
    61. }
    62. public RowMergeWriterHandler(Set<Integer> mergeCols) {
    63. this.mergeCols = mergeCols;
    64. }
    65. @Override
    66. protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
    67. if (CollectionUtils.isNotEmpty(mergeCols) && !mergeCols.contains(cell.getColumnIndex())) {
    68. return;
    69. }
    70. mergeCell(cell.getSheet(), cell, CellMergeEnum.ROW);
    71. }
    72. }
    73. private static void mergeCell(Sheet sheet, Cell cell, CellMergeEnum cellMergeEnum) {
    74. if (Objects.isNull(cell)) {
    75. return;
    76. }
    77. int rowIndex = cell.getRowIndex(), colIndex = cell.getColumnIndex();
    78. Row preRow = null;
    79. Cell preCell = null;
    80. if (CellMergeEnum.ROW.equals(cellMergeEnum)) {
    81. if (rowIndex == 0) {
    82. return;
    83. }
    84. preRow = sheet.getRow(rowIndex - 1);
    85. if (Objects.isNull(preRow)) {
    86. return;
    87. }
    88. preCell = preRow.getCell(colIndex);
    89. }
    90. if (CellMergeEnum.COLUMN.equals(cellMergeEnum)) {
    91. if (colIndex == 0) {
    92. return;
    93. }
    94. preRow = cell.getRow();
    95. preCell = preRow.getCell(colIndex - 1);
    96. }
    97. if (Objects.isNull(preCell)) {
    98. return;
    99. }
    100. Object preCellValue = getCellValue(preCell), curCellValue = getCellValue(cell);
    101. if (Objects.isNull(preCellValue) || Objects.isNull(curCellValue) || !preCellValue.equals(curCellValue)) {
    102. return;
    103. }
    104. merge(sheet, preCell, cell);
    105. }
    106. private static void merge(Sheet sheet, Cell preCell, Cell curCell) {
    107. List<CellRangeAddress> list = sheet.getMergedRegions();
    108. if (CollectionUtils.isEmpty(list)) {
    109. sheet.addMergedRegionUnsafe(new CellRangeAddress(preCell.getRowIndex(), curCell.getRowIndex(), preCell.getColumnIndex(), curCell.getColumnIndex()));
    110. return;
    111. }
    112. for (int i = 0; i < list.size(); i++) {
    113. CellRangeAddress cellRangeAddress = list.get(i);
    114. if (cellRangeAddress.containsRow(preCell.getRowIndex()) && cellRangeAddress.containsColumn(preCell.getColumnIndex())) {
    115. int firstRowIndex = cellRangeAddress.getFirstRow(), firstColIndex = cellRangeAddress.getFirstColumn();
    116. sheet.removeMergedRegion(i);
    117. sheet.addMergedRegionUnsafe(new CellRangeAddress(firstRowIndex, curCell.getRowIndex(), firstColIndex, curCell.getColumnIndex()));
    118. return;
    119. }
    120. }
    121. sheet.addMergedRegionUnsafe(new CellRangeAddress(preCell.getRowIndex(), curCell.getRowIndex(), preCell.getColumnIndex(), curCell.getColumnIndex()));
    122. }
    123. protected static Object getCellValue(Cell cell) {
    124. if (Objects.isNull(cell)) {
    125. return null;
    126. }
    127. CellType cellTypeEnum = cell.getCellType();
    128. switch (cellTypeEnum) {
    129. case STRING:
    130. return cell.getStringCellValue();
    131. case BOOLEAN:
    132. return cell.getBooleanCellValue();
    133. case NUMERIC:
    134. return cell.getNumericCellValue();
    135. default:
    136. return null;
    137. }
    138. }
    139. public enum CellMergeEnum {
    140. /**
    141. * row
    142. */
    143. ROW,
    144. /**
    145. * column
    146. */
    147. COLUMN;
    148. }
    149. }

    测试代码:

    1. @Test
    2. public void testTemplate() {
    3. String templateFileName = "./src/test/resources/test_simple_list.xlsx";
    4. String fileName = "./reports/listFill" + System.currentTimeMillis() + ".xlsx";
    5. ByteArrayOutputStream out = new ByteArrayOutputStream();
    6. ExcelWriter excelWriter = EasyExcel.write(out).withTemplate(templateFileName)
    7. .registerWriteHandler(CellMergeWriterHandler.getRowMergeWriterHandler(Arrays.asList(0, 1)))
    8. .autoCloseStream(Boolean.FALSE)
    9. .build();
    10. WriteSheet writeSheet = EasyExcel.writerSheet(0).build();
    11. // 直接写入数据
    12. FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
    13. excelWriter.fill(dataMap(), fillConfig, writeSheet);
    14. excelWriter.finish();
    15. File file = new File(fileName);
    16. try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {
    17. fileOutputStream.write(out.toByteArray());
    18. fileOutputStream.flush();
    19. } catch (Exception e) {
    20. e.printStackTrace();
    21. }
    22. }
    23. private List<Map<String, Object>> dataMap() {
    24. List<Map<String, Object>> list = ListUtils.newArrayList();
    25. for (int i = 0; i < 5; i++) {
    26. Map<String, Object> object = new HashMap<>();
    27. list.add(object);
    28. if (i % 3 == 0) {
    29. object.put("name", "张三3");
    30. object.put("number", null);
    31. } else {
    32. object.put("number", 5.2);
    33. object.put("name", "张三");
    34. }
    35. }
    36. return list;
    37. }

    模板:
    image.png
    运行效果:
    image.png
    A列和B列相同数值行合并。