Browse Source

feat: 支持动态列的写入,基于实体对象类,实现动态变更列的顺序和列名

pull/2565/head
WangFaRui 3 years ago
parent
commit
9a611fd70d
  1. 11
      easyexcel-core/src/main/java/com/alibaba/excel/metadata/Head.java
  2. 32
      easyexcel-core/src/main/java/com/alibaba/excel/metadata/entity/ExcelExportEntity.java
  3. 113
      easyexcel-core/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java
  4. 17
      easyexcel-core/src/main/java/com/alibaba/excel/util/FieldUtils.java
  5. 23
      easyexcel-core/src/main/java/com/alibaba/excel/write/builder/AbstractExcelWriterParameterBuilder.java
  6. 10
      easyexcel-core/src/main/java/com/alibaba/excel/write/metadata/WriteBasicParameter.java
  7. 19
      easyexcel-core/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java
  8. 47
      easyexcel-test/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java

11
easyexcel-core/src/main/java/com/alibaba/excel/metadata/Head.java

@ -66,6 +66,17 @@ public class Head {
*/
private FontProperty headFontProperty;
public Head(Integer columnIndex, Field field, String fieldName, String headName) {
this.columnIndex = columnIndex;
this.field = field;
this.fieldName = fieldName;
List<String> headNameList = new ArrayList<>();
headNameList.add(headName);
this.headNameList = headNameList;
this.forceIndex = true;
this.forceName = true;
}
public Head(Integer columnIndex, Field field, String fieldName, List<String> headNameList, Boolean forceIndex,
Boolean forceName) {
this.columnIndex = columnIndex;

32
easyexcel-core/src/main/java/com/alibaba/excel/metadata/entity/ExcelExportEntity.java

@ -0,0 +1,32 @@
package com.alibaba.excel.metadata.entity;
import lombok.Getter;
import lombok.Setter;
/**
* Excel export dynamic column entity
*
* @author wangfarui
* @since 2022/6/27
*/
@Getter
@Setter
public class ExcelExportEntity {
/**
* data field name
*/
private String key;
/**
* Table column name
*/
private String name;
public ExcelExportEntity() {}
public ExcelExportEntity(String key, String name) {
this.key = key;
this.name = name;
}
}

113
easyexcel-core/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java

@ -1,16 +1,14 @@
package com.alibaba.excel.metadata.property;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.*;
import java.util.stream.Collectors;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.enums.HeadKindEnum;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.Holder;
import com.alibaba.excel.metadata.entity.ExcelExportEntity;
import com.alibaba.excel.util.ClassUtils;
import com.alibaba.excel.util.FieldUtils;
import com.alibaba.excel.util.MapUtils;
@ -62,21 +60,41 @@ public class ExcelHeadProperty {
ignoreMap = MapUtils.newHashMap();
headKind = HeadKindEnum.NONE;
headRowNumber = 0;
if (head != null && !head.isEmpty()) {
int headIndex = 0;
for (int i = 0; i < head.size(); i++) {
if (holder instanceof AbstractWriteHolder) {
if (((AbstractWriteHolder)holder).ignore(null, i)) {
continue;
if (headClazz == null) {
if (LOGGER.isWarnEnabled()) {
LOGGER.warn("The current sheet/table is not specified with headClazz");
}
return;
}
// dynamic column
if (holder instanceof AbstractWriteHolder &&
(!CollectionUtils.isEmpty(((AbstractWriteHolder) holder).getDynamicColumnFieldNames())
|| !CollectionUtils.isEmpty(((AbstractWriteHolder) holder).getDynamicColumnEntities()))) {
if (!CollectionUtils.isEmpty(((AbstractWriteHolder) holder).getDynamicColumnFieldNames())) {
initColumnNameProperties(((AbstractWriteHolder) holder).getDynamicColumnFieldNames());
}
if (!CollectionUtils.isEmpty(((AbstractWriteHolder) holder).getDynamicColumnEntities())) {
initColumnEntityProperties(((AbstractWriteHolder) holder).getDynamicColumnEntities());
}
} else {
if (head != null && !head.isEmpty()) {
int headIndex = 0;
for (int i = 0; i < head.size(); i++) {
if (holder instanceof AbstractWriteHolder) {
if (((AbstractWriteHolder)holder).ignore(null, i)) {
continue;
}
}
headMap.put(headIndex, new Head(headIndex, null, null, head.get(i), Boolean.FALSE, Boolean.TRUE));
headIndex++;
}
headMap.put(headIndex, new Head(headIndex, null, null, head.get(i), Boolean.FALSE, Boolean.TRUE));
headIndex++;
headKind = HeadKindEnum.STRING;
}
headKind = HeadKindEnum.STRING;
// convert headClazz to head
initColumnProperties(holder);
}
// convert headClazz to head
initColumnProperties(holder);
initHeadRowNumber();
if (LOGGER.isDebugEnabled()) {
@ -104,6 +122,57 @@ public class ExcelHeadProperty {
}
}
private void initColumnNameProperties(Collection<String> dynamicColumnFieldNames) {
headKind = HeadKindEnum.CLASS;
int i = 0;
List<Field> fields = FieldUtils.getAllFields(headClazz);
for (String filedName : dynamicColumnFieldNames) {
for (Field field : fields) {
if (filedName.equals(field.getName())) {
initOneColumnProperty(i++, field, true);
break;
}
}
}
if (headMap.size() == fields.size()) {
return;
}
for (Field field : fields) {
if (!dynamicColumnFieldNames.contains(field.getName())) {
ignoreMap.put(field.getName(), field);
}
}
}
private void initColumnEntityProperties(Collection<ExcelExportEntity> dynamicColumnEntities) {
headKind = HeadKindEnum.CLASS;
int i = 0;
List<Field> fields = FieldUtils.getAllFields(headClazz);
for (ExcelExportEntity entity : dynamicColumnEntities) {
for (Field field : fields) {
if (field.getName().equals(entity.getKey())) {
initOneColumnProperty(i++, field, entity);
break;
}
}
}
if (headMap.size() == fields.size()) {
return;
}
Set<String> keyList = dynamicColumnEntities.stream().map(ExcelExportEntity::getKey).collect(Collectors.toSet());
for (Field field : fields) {
if (!keyList.contains(field.getName())) {
ignoreMap.put(field.getName(), field);
}
}
}
private void initColumnProperties(Holder holder) {
if (headClazz == null) {
return;
@ -153,6 +222,18 @@ public class ExcelHeadProperty {
headMap.put(index, head);
}
/**
* Initialization column property
*
* @param index map index
* @param field the current field
* @param entity ExcelExportEntity
*/
private void initOneColumnProperty(int index, Field field, ExcelExportEntity entity) {
Head head = new Head(index, field, entity.getKey(), entity.getName());
headMap.put(index, head);
}
public boolean hasHead() {
return headKind != HeadKindEnum.NONE;
}

17
easyexcel-core/src/main/java/com/alibaba/excel/util/FieldUtils.java

@ -2,6 +2,9 @@ package com.alibaba.excel.util;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.alibaba.excel.metadata.NullObject;
@ -166,4 +169,18 @@ public class FieldUtils {
return match;
}
/**
* Gets the fields of the current class and its parent class
* @param clazz
* @return
*/
public static List<Field> getAllFields(Class<?> clazz) {
List<Field> fields = new ArrayList<>();
while (clazz != null) {
Collections.addAll(fields, clazz.getDeclaredFields());
clazz = clazz.getSuperclass();
}
return fields;
}
}

23
easyexcel-core/src/main/java/com/alibaba/excel/write/builder/AbstractExcelWriterParameterBuilder.java

@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.Collection;
import com.alibaba.excel.metadata.AbstractParameterBuilder;
import com.alibaba.excel.metadata.entity.ExcelExportEntity;
import com.alibaba.excel.write.handler.WriteHandler;
import com.alibaba.excel.write.metadata.WriteBasicParameter;
@ -120,4 +121,26 @@ public abstract class AbstractExcelWriterParameterBuilder<T extends AbstractExce
parameter().setIncludeColumnFieldNames(includeColumnFieldNames);
return self();
}
public T setDynamicColumnFieldNames(Collection<String> dynamicColumnFieldNames) {
return setDynamicColumnFieldNames(true, dynamicColumnFieldNames);
}
public T setDynamicColumnFieldNames(Boolean bool, Collection<String> dynamicColumnFieldNames) {
if (bool) {
parameter().setDynamicColumnFieldNames(dynamicColumnFieldNames);
}
return self();
}
public T setDynamicColumnEntities(Collection<ExcelExportEntity> dynamicColumnEntities) {
return setDynamicColumnEntities(true, dynamicColumnEntities);
}
public T setDynamicColumnEntities(Boolean bool, Collection<ExcelExportEntity> dynamicColumnEntities) {
if (bool) {
parameter().setDynamicColumnEntities(dynamicColumnEntities);
}
return self();
}
}

10
easyexcel-core/src/main/java/com/alibaba/excel/write/metadata/WriteBasicParameter.java

@ -5,6 +5,7 @@ import java.util.Collection;
import java.util.List;
import com.alibaba.excel.metadata.BasicParameter;
import com.alibaba.excel.metadata.entity.ExcelExportEntity;
import com.alibaba.excel.write.handler.WriteHandler;
import lombok.EqualsAndHashCode;
@ -56,4 +57,13 @@ public class WriteBasicParameter extends BasicParameter {
* Only output the custom columns.
*/
private Collection<String> includeColumnFieldNames;
/**
* Dynamic column field name
*/
private Collection<String> dynamicColumnFieldNames;
/**
* Dynamic column entity
*/
private Collection<ExcelExportEntity> dynamicColumnEntities;
}

19
easyexcel-core/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java

@ -17,6 +17,7 @@ import com.alibaba.excel.enums.HeadKindEnum;
import com.alibaba.excel.event.NotRepeatExecutor;
import com.alibaba.excel.metadata.AbstractHolder;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.entity.ExcelExportEntity;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.metadata.property.LoopMergeProperty;
import com.alibaba.excel.metadata.property.OnceAbsoluteMergeProperty;
@ -94,6 +95,14 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
* Only output the custom columns.
*/
private Collection<String> includeColumnFieldNames;
/**
* Dynamic column field name
*/
private Collection<String> dynamicColumnFieldNames;
/**
* Dynamic column entity
*/
private Collection<ExcelExportEntity> dynamicColumnEntities;
/**
* Write handler
@ -199,6 +208,16 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
} else {
this.includeColumnIndexes = writeBasicParameter.getIncludeColumnIndexes();
}
if (writeBasicParameter.getDynamicColumnFieldNames() == null && parentAbstractWriteHolder != null) {
this.dynamicColumnFieldNames = parentAbstractWriteHolder.getDynamicColumnFieldNames();
} else {
this.dynamicColumnFieldNames = writeBasicParameter.getDynamicColumnFieldNames();
}
if (writeBasicParameter.getDynamicColumnEntities() == null && parentAbstractWriteHolder != null) {
this.dynamicColumnEntities = parentAbstractWriteHolder.getDynamicColumnEntities();
} else {
this.dynamicColumnEntities = writeBasicParameter.getDynamicColumnEntities();
}
// Initialization property
this.excelWriteHeadProperty = new ExcelWriteHeadProperty(this, getClazz(), getHead());

47
easyexcel-test/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java

@ -27,6 +27,7 @@ import com.alibaba.excel.metadata.data.ImageData;
import com.alibaba.excel.metadata.data.ImageData.ImageType;
import com.alibaba.excel.metadata.data.RichTextStringData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.entity.ExcelExportEntity;
import com.alibaba.excel.util.BooleanUtils;
import com.alibaba.excel.util.FileUtils;
import com.alibaba.excel.util.ListUtils;
@ -452,7 +453,7 @@ public class WriteTest {
// 背景设置为红色
headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());
WriteFont headWriteFont = new WriteFont();
headWriteFont.setFontHeightInPoints((short)20);
headWriteFont.setFontHeightInPoints((short) 20);
headWriteCellStyle.setWriteFont(headWriteFont);
// 内容的策略
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
@ -462,7 +463,7 @@ public class WriteTest {
contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex());
WriteFont contentWriteFont = new WriteFont();
// 字体大小
contentWriteFont.setFontHeightInPoints((short)20);
contentWriteFont.setFontHeightInPoints((short) 20);
contentWriteCellStyle.setWriteFont(contentWriteFont);
// 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
HorizontalCellStyleStrategy horizontalCellStyleStrategy =
@ -697,6 +698,48 @@ public class WriteTest {
EasyExcel.write(fileName).head(head()).sheet("模板").doWrite(dataList());
}
/**
* 实时生成列写入, 简化 {@link this#dynamicHeadWrite()} 的数据结构
* <p>相较于 dynamicHeadWrite() 方法, 此方法无需双层集合, 适用于简单表格的导出.
* <p>表格样式仍然基于数据类的注解属性, 在此基础上可以指定只导出指定列, 并且导出列的顺序由集合的有序性决定.
*/
@Test
public void dynamicColumnFieldWrite() {
String fileName = TestFileUtil.getPath() + "dynamicColumnFieldWrite" + System.currentTimeMillis() + ".xlsx";
List<String> fieldNames = new ArrayList<>();
fieldNames.add("date");
fieldNames.add("string");
EasyExcel.write(fileName, DemoData.class)
.setDynamicColumnFieldNames(fieldNames)
.sheet("测试实时生成列")
.doWrite(data());
System.out.println(fileName);
}
/**
* 动态列的写入, 基于{@link ExcelExportEntity}实体集合实现
* <p>表格样式仍然基于数据类的注解属性, 在此基础上可以指定导出列以及列名称, 并且导出列的顺序由集合的有序性决定.
* <p>一般用于导出列名可以由用户编辑的业务场景.
*/
@Test
public void dynamicColumnEntityWrite() {
String fileName = TestFileUtil.getPath() + "dynamicColumnEntityWrite" + System.currentTimeMillis() + ".xlsx";
List<ExcelExportEntity> fieldEntities = new ArrayList<>();
fieldEntities.add(new ExcelExportEntity("string", "字符串"));
fieldEntities.add(new ExcelExportEntity("date", "日期"));
EasyExcel.write(fileName, DemoData.class)
.setDynamicColumnEntities(fieldEntities)
.sheet("测试动态实体列")
.doWrite(data());
System.out.println(fileName);
}
private List<LongestMatchColumnWidthData> dataLong() {
List<LongestMatchColumnWidthData> list = ListUtils.newArrayList();
for (int i = 0; i < 10; i++) {

Loading…
Cancel
Save