CellMergeStrategy.java 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. package com.ruoyi.common.excel;
  2. import cn.hutool.core.collection.CollUtil;
  3. import com.alibaba.excel.annotation.ExcelProperty;
  4. import com.alibaba.excel.metadata.Head;
  5. import com.alibaba.excel.write.merge.AbstractMergeStrategy;
  6. import com.ruoyi.common.annotation.CellMerge;
  7. import com.ruoyi.common.utils.reflect.ReflectUtils;
  8. import lombok.AllArgsConstructor;
  9. import lombok.Data;
  10. import lombok.SneakyThrows;
  11. import lombok.extern.slf4j.Slf4j;
  12. import org.apache.poi.ss.usermodel.Cell;
  13. import org.apache.poi.ss.usermodel.Sheet;
  14. import org.apache.poi.ss.util.CellRangeAddress;
  15. import java.lang.reflect.Field;
  16. import java.util.ArrayList;
  17. import java.util.HashMap;
  18. import java.util.List;
  19. import java.util.Map;
  20. /**
  21. * 列值重复合并策略
  22. *
  23. * @author Lion Li
  24. */
  25. @Slf4j
  26. public class CellMergeStrategy extends AbstractMergeStrategy {
  27. private final List<CellRangeAddress> cellList;
  28. private final boolean hasTitle;
  29. private int rowIndex;
  30. public CellMergeStrategy(List<?> list, boolean hasTitle) {
  31. this.hasTitle = hasTitle;
  32. // 行合并开始下标
  33. this.rowIndex = hasTitle ? 1 : 0;
  34. this.cellList = handle(list, hasTitle);
  35. }
  36. @Override
  37. protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
  38. // judge the list is not null
  39. if (CollUtil.isNotEmpty(cellList)) {
  40. // the judge is necessary
  41. if (cell.getRowIndex() == rowIndex && cell.getColumnIndex() == 0) {
  42. for (CellRangeAddress item : cellList) {
  43. sheet.addMergedRegion(item);
  44. }
  45. }
  46. }
  47. }
  48. @SneakyThrows
  49. private List<CellRangeAddress> handle(List<?> list, boolean hasTitle) {
  50. List<CellRangeAddress> cellList = new ArrayList<>();
  51. if (CollUtil.isEmpty(list)) {
  52. return cellList;
  53. }
  54. Field[] fields = ReflectUtils.getFields(list.get(0).getClass(), field -> !"serialVersionUID".equals(field.getName()));
  55. // 有注解的字段
  56. List<Field> mergeFields = new ArrayList<>();
  57. List<Integer> mergeFieldsIndex = new ArrayList<>();
  58. for (int i = 0; i < fields.length; i++) {
  59. Field field = fields[i];
  60. if (field.isAnnotationPresent(CellMerge.class)) {
  61. CellMerge cm = field.getAnnotation(CellMerge.class);
  62. mergeFields.add(field);
  63. mergeFieldsIndex.add(cm.index() == -1 ? i : cm.index());
  64. if (hasTitle) {
  65. ExcelProperty property = field.getAnnotation(ExcelProperty.class);
  66. rowIndex = Math.max(rowIndex, property.value().length);
  67. }
  68. }
  69. }
  70. Map<Field, RepeatCell> map = new HashMap<>();
  71. // 生成两两合并单元格
  72. for (int i = 0; i < list.size(); i++) {
  73. for (int j = 0; j < mergeFields.size(); j++) {
  74. Field field = mergeFields.get(j);
  75. Object val = ReflectUtils.invokeGetter(list.get(i), field.getName());
  76. int colNum = mergeFieldsIndex.get(j);
  77. if (!map.containsKey(field)) {
  78. map.put(field, new RepeatCell(val, i));
  79. } else {
  80. RepeatCell repeatCell = map.get(field);
  81. Object cellValue = repeatCell.getValue();
  82. if (cellValue == null || "".equals(cellValue)) {
  83. // 空值跳过不合并
  84. continue;
  85. }
  86. if (!cellValue.equals(val)) {
  87. if (i - repeatCell.getCurrent() > 1) {
  88. cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum));
  89. }
  90. map.put(field, new RepeatCell(val, i));
  91. } else if (i == list.size() - 1) {
  92. if (i > repeatCell.getCurrent()) {
  93. cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum));
  94. }
  95. }
  96. }
  97. }
  98. }
  99. return cellList;
  100. }
  101. @Data
  102. @AllArgsConstructor
  103. static class RepeatCell {
  104. private Object value;
  105. private int current;
  106. }
  107. }