package com.alibaba.excel.metadata.property; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.TreeMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.excel.annotation.ExcelIgnore; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.format.DateTimeFormat; import com.alibaba.excel.annotation.format.NumberFormat; import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.alibaba.excel.annotation.write.style.ContentRowHeight; import com.alibaba.excel.annotation.write.style.ContentStyle; import com.alibaba.excel.annotation.write.style.HeadRowHeight; import com.alibaba.excel.annotation.write.style.HeadStyle; import com.alibaba.excel.enums.HeadKindEnum; import com.alibaba.excel.exception.ExcelGenerateException; import com.alibaba.excel.metadata.CellRange; import com.alibaba.excel.metadata.Head; /** * Define the header attribute of excel * * @author jipengfei */ public class ExcelHeadProperty { private static final Logger LOGGER = LoggerFactory.getLogger(ExcelHeadProperty.class); /** * Custom class */ private Class headClazz; /** * The types of head */ private HeadKindEnum headKind; /** * The number of rows in the line with the most rows */ private int headRowNumber; /** * Configuration header information */ private Map headMap; /** * Configuration column information */ private Map contentPropertyMap; private RowHeightProperty headRowHeightProperty; private RowHeightProperty contentRowHeightProperty; public ExcelHeadProperty(Class headClazz, List> head, Boolean convertAllFiled) { this.headClazz = headClazz; headMap = new TreeMap(); contentPropertyMap = new TreeMap(); headKind = HeadKindEnum.NONE; headRowNumber = 0; if (head != null && !head.isEmpty()) { for (int i = 0; i < head.size(); i++) { headMap.put(i, new Head(i, null, head.get(i))); contentPropertyMap.put(i, null); } headKind = HeadKindEnum.STRING; } else { // convert headClazz to head initColumnProperties(convertAllFiled); } initHeadRowNumber(); LOGGER.info("The initialization sheet/table 'ExcelHeadProperty' is complete , head kind is {}", headKind); if (!hasHead()) { LOGGER.warn( "The table has no header set and all annotations will not be read.If you want to use annotations, please use set head class in ExcelWriterBuilder/ExcelWriterSheetBuilder/ExcelWriterTableBuilder"); } } public static ExcelHeadProperty buildExcelHeadProperty(ExcelHeadProperty excelHeadProperty, Class clazz, List headOneRow) { if (excelHeadProperty == null) { return new ExcelHeadProperty(clazz, new ArrayList>(), false); } if (headOneRow != null) { excelHeadProperty.appendOneRow(headOneRow); } return excelHeadProperty; } private void initHeadRowNumber() { headRowNumber = 0; for (Head head : headMap.values()) { List list = head.getHeadNameList(); if (list != null && list.size() > headRowNumber) { headRowNumber = list.size(); } } for (Head head : headMap.values()) { List list = head.getHeadNameList(); if (list != null && !list.isEmpty() && list.size() < headRowNumber) { int lack = headRowNumber - list.size(); int last = list.size() - 1; for (int i = 0; i < lack; i++) { list.add(list.get(last)); } } } } private void initColumnProperties(Boolean convertAllFiled) { if (headClazz == null) { return; } List fieldList = new ArrayList(); Class tempClass = headClazz; // When the parent class is null, it indicates that the parent class (Object class) has reached the top // level. while (tempClass != null) { fieldList.addAll(Arrays.asList(tempClass.getDeclaredFields())); // Get the parent class and give it to yourself tempClass = tempClass.getSuperclass(); } // Screening of field List defaultFieldList = new ArrayList(); Map customFiledMap = new TreeMap(); for (Field field : fieldList) { ExcelIgnore excelIgnore = field.getAnnotation(ExcelIgnore.class); if (excelIgnore != null) { continue; } ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); if (excelProperty == null && !convertAllFiled) { continue; } if (excelProperty == null || excelProperty.index() < 0) { defaultFieldList.add(field); continue; } if (customFiledMap.containsKey(excelProperty.index())) { throw new ExcelGenerateException("The index of " + customFiledMap.get(excelProperty.index()).getName() + " and " + field.getName() + " must be inconsistent"); } customFiledMap.put(excelProperty.index(), field); } HeadStyle headStyle = (HeadStyle)headClazz.getAnnotation(HeadStyle.class); ContentStyle contentStyle = (ContentStyle)headClazz.getAnnotation(ContentStyle.class); ColumnWidth columnWidth = (ColumnWidth)headClazz.getAnnotation(ColumnWidth.class); this.headRowHeightProperty = RowHeightProperty.build((HeadRowHeight)headClazz.getAnnotation(HeadRowHeight.class)); this.contentRowHeightProperty = RowHeightProperty.build((ContentRowHeight)headClazz.getAnnotation(ContentRowHeight.class)); int index = 0; for (Field field : defaultFieldList) { while (customFiledMap.containsKey(index)) { initOneColumnProperty(index, customFiledMap.get(index), headStyle, contentStyle, columnWidth); customFiledMap.remove(index); index++; } initOneColumnProperty(index, field, headStyle, contentStyle, columnWidth); index++; } for (Map.Entry entry : customFiledMap.entrySet()) { initOneColumnProperty(index, entry.getValue(), headStyle, contentStyle, columnWidth); index++; } headKind = HeadKindEnum.CLASS; } private void initOneColumnProperty(int index, Field field, HeadStyle parentHeadStyle, ContentStyle parentContentStyle, ColumnWidth parentColumnWidth) { ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); List tmpHeadList = new ArrayList(); if (excelProperty != null) { tmpHeadList = Arrays.asList(excelProperty.value()); } else { tmpHeadList.add(field.getName()); } Head head = new Head(index, field.getName(), tmpHeadList); HeadStyle headStyle = field.getAnnotation(HeadStyle.class); if (headStyle == null) { headStyle = parentHeadStyle; } head.setCellStyleProperty(CellStyleProperty.build(headStyle)); ColumnWidth columnWidth = field.getAnnotation(ColumnWidth.class); if (columnWidth == null) { columnWidth = parentColumnWidth; } head.setColumnWidthProperty(ColumnWidthProperty.build(columnWidth)); ExcelContentProperty excelContentProperty = new ExcelContentProperty(); excelContentProperty.setHead(head); excelContentProperty.setField(field); ContentStyle contentStyle = field.getAnnotation(ContentStyle.class); if (contentStyle == null) { contentStyle = parentContentStyle; } excelContentProperty.setCellStyleProperty(CellStyleProperty.build(contentStyle)); excelContentProperty .setDateTimeFormatProperty(DateTimeFormatProperty.build(field.getAnnotation(DateTimeFormat.class))); excelContentProperty .setNumberFormatProperty(NumberFormatProperty.build(field.getAnnotation(NumberFormat.class))); headMap.put(index, head); contentPropertyMap.put(index, excelContentProperty); } /** * Add one more head under the last head */ public void appendOneRow(List row) { for (int i = 0; i < row.size(); i++) { String rowData = row.get(i); // join if (headMap.containsKey(i)) { headMap.get(i).getHeadNameList().add(rowData); } else { // create and join int index = ((TreeMap)headMap).lastKey() + 1; headMap.put(index, new Head(i, null, rowData)); } } initHeadRowNumber(); } public Class getHeadClazz() { return headClazz; } public void setHeadClazz(Class headClazz) { this.headClazz = headClazz; } public HeadKindEnum getHeadKind() { return headKind; } public void setHeadKind(HeadKindEnum headKind) { this.headKind = headKind; } public boolean hasHead() { return headKind != HeadKindEnum.NONE; } public int getHeadRowNumber() { return headRowNumber; } public void setHeadRowNumber(int headRowNumber) { this.headRowNumber = headRowNumber; } public Map getHeadMap() { return headMap; } public void setHeadMap(Map headMap) { this.headMap = headMap; } public Map getContentPropertyMap() { return contentPropertyMap; } public void setContentPropertyMap(Map contentPropertyMap) { this.contentPropertyMap = contentPropertyMap; } public RowHeightProperty getHeadRowHeightProperty() { return headRowHeightProperty; } public void setHeadRowHeightProperty(RowHeightProperty headRowHeightProperty) { this.headRowHeightProperty = headRowHeightProperty; } public RowHeightProperty getContentRowHeightProperty() { return contentRowHeightProperty; } public void setContentRowHeightProperty(RowHeightProperty contentRowHeightProperty) { this.contentRowHeightProperty = contentRowHeightProperty; } /** * Calculate all cells that need to be merged * * @return cells that need to be merged */ public List headCellRangeList() { List cellRangeList = new ArrayList(); int i = 0; for (Map.Entry entry : headMap.entrySet()) { Head head = entry.getValue(); List columnValues = head.getHeadNameList(); for (int j = 0; j < columnValues.size(); j++) { int lastRow = getLastRangNum(j, columnValues.get(j), columnValues); int lastColumn = getLastRangNum(i, columnValues.get(j), head.getHeadNameList()); if ((lastRow > j || lastColumn > i) && lastRow >= 0 && lastColumn >= 0) { cellRangeList.add(new CellRange(j, lastRow, i, lastColumn)); } } i++; } return cellRangeList; } /** * Get the last consecutive string position * * @param j * current value position * @param value * value content * @param values * values * @return the last consecutive string position */ private int getLastRangNum(int j, String value, List values) { if (value == null) { return -1; } if (j > 0) { String preValue = values.get(j - 1); if (value.equals(preValue)) { return -1; } } int last = j; for (int i = last + 1; i < values.size(); i++) { String current = values.get(i); if (value.equals(current)) { last = i; } else { // if i>j && !value.equals(current) Indicates that the continuous range is exceeded if (i > j) { break; } } } return last; } }