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