Browse Source

* 默认对象反射缓存改成`ThreadLocal`,并支持设置 [Issue #2792](https://github.com/alibaba/easyexcel/issues/2792)

* 支持根据`includeColumnIndexes`和`includeColumnFieldNames`排序 [Issue #2697](https://github.com/alibaba/easyexcel/issues/2697)
pull/3168/head
Jiaju Zhuang 2 years ago
parent
commit
e9856e5549
  1. 2
      easyexcel-core/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java
  2. 3
      easyexcel-core/src/main/java/com/alibaba/excel/context/WriteContextImpl.java
  3. 23
      easyexcel-core/src/main/java/com/alibaba/excel/enums/CacheLocationEnum.java
  4. 9
      easyexcel-core/src/main/java/com/alibaba/excel/metadata/AbstractHolder.java
  5. 8
      easyexcel-core/src/main/java/com/alibaba/excel/metadata/BasicParameter.java
  6. 37
      easyexcel-core/src/main/java/com/alibaba/excel/metadata/FieldCache.java
  7. 11
      easyexcel-core/src/main/java/com/alibaba/excel/metadata/GlobalConfiguration.java
  8. 34
      easyexcel-core/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java
  9. 3
      easyexcel-core/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java
  10. 5
      easyexcel-core/src/main/java/com/alibaba/excel/read/metadata/property/ExcelReadHeadProperty.java
  11. 435
      easyexcel-core/src/main/java/com/alibaba/excel/util/ClassUtils.java
  12. 9
      easyexcel-core/src/main/java/com/alibaba/excel/write/builder/AbstractExcelWriterParameterBuilder.java
  13. 29
      easyexcel-core/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java
  14. 8
      easyexcel-core/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java
  15. 7
      easyexcel-core/src/main/java/com/alibaba/excel/write/metadata/WriteBasicParameter.java
  16. 45
      easyexcel-core/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java
  17. 29
      easyexcel-core/src/main/java/com/alibaba/excel/write/metadata/holder/WriteHolder.java
  18. 1
      easyexcel-core/src/main/java/com/alibaba/excel/write/metadata/holder/WriteWorkbookHolder.java
  19. 5
      easyexcel-core/src/main/java/com/alibaba/excel/write/property/ExcelWriteHeadProperty.java
  20. 14
      easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/excludeorinclude/ExcludeOrIncludeDataTest.java
  21. 5
      update.md

2
easyexcel-core/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java

@ -19,6 +19,7 @@ import com.alibaba.excel.read.metadata.holder.csv.CsvReadWorkbookHolder;
import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder;
import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.util.ClassUtils;
import com.alibaba.excel.util.DateUtils;
import com.alibaba.excel.util.FileUtils;
import com.alibaba.excel.util.NumberDataFormatterUtils;
@ -212,6 +213,7 @@ public class ExcelAnalyserImpl implements ExcelAnalyser {
private void removeThreadLocalCache() {
NumberDataFormatterUtils.removeThreadLocalCache();
DateUtils.removeThreadLocalCache();
ClassUtils.removeThreadLocalCache();
}
private void clearEncrypt03() {

3
easyexcel-core/src/main/java/com/alibaba/excel/context/WriteContextImpl.java

@ -265,7 +265,7 @@ public class WriteContextImpl implements WriteContext {
Head head = entry.getValue();
int columnIndex = entry.getKey();
ExcelContentProperty excelContentProperty = ClassUtils.declaredExcelContentProperty(null,
currentWriteHolder.excelWriteHeadProperty().getHeadClazz(), head.getFieldName());
currentWriteHolder.excelWriteHeadProperty().getHeadClazz(), head.getFieldName(), currentWriteHolder);
CellWriteHandlerContext cellWriteHandlerContext = WriteHandlerUtils.createCellWriteHandlerContext(this, row,
rowIndex, head, columnIndex, relativeRowIndex, Boolean.TRUE, excelContentProperty);
@ -427,6 +427,7 @@ public class WriteContextImpl implements WriteContext {
private void removeThreadLocalCache() {
NumberDataFormatterUtils.removeThreadLocalCache();
DateUtils.removeThreadLocalCache();
ClassUtils.removeThreadLocalCache();
}
@Override

23
easyexcel-core/src/main/java/com/alibaba/excel/enums/CacheLocationEnum.java

@ -0,0 +1,23 @@
package com.alibaba.excel.enums;
/**
* cache locaciton
*
* @author Jiaju Zhuang
**/
public enum CacheLocationEnum {
/**
* The cache will be stored in {@code ThreadLocal}, and will be cleared when the excel read and write is completed.
*/
THREAD_LOCAL,
/**
* The cache will not be cleared unless the app is stopped.
*/
MEMORY,
/**
* No caching.It may lose some of performance.
*/
NONE;
}

9
easyexcel-core/src/main/java/com/alibaba/excel/metadata/AbstractHolder.java

@ -83,6 +83,15 @@ public abstract class AbstractHolder implements ConfigurationHolder {
globalConfiguration.setLocale(basicParameter.getLocale());
}
if (basicParameter.getFiledCacheLocation() == null) {
if (prentAbstractHolder != null) {
globalConfiguration.setFiledCacheLocation(
prentAbstractHolder.getGlobalConfiguration().getFiledCacheLocation());
}
} else {
globalConfiguration.setFiledCacheLocation(basicParameter.getFiledCacheLocation());
}
}
@Override

8
easyexcel-core/src/main/java/com/alibaba/excel/metadata/BasicParameter.java

@ -4,6 +4,7 @@ import java.util.List;
import java.util.Locale;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CacheLocationEnum;
import lombok.EqualsAndHashCode;
import lombok.Getter;
@ -54,4 +55,11 @@ public class BasicParameter {
* default is false
*/
private Boolean useScientificFormat;
/**
* The cache used when parsing fields such as head.
*
* default is THREAD_LOCAL.
*/
private CacheLocationEnum filedCacheLocation;
}

37
easyexcel-core/src/main/java/com/alibaba/excel/metadata/FieldCache.java

@ -0,0 +1,37 @@
package com.alibaba.excel.metadata;
import java.lang.reflect.Field;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
/**
* filed cache
*
* @author Jiaju Zhuang
*/
@Getter
@Setter
@EqualsAndHashCode
@AllArgsConstructor
public class FieldCache {
/**
* A field cache that has been sorted by a class.
* It will exclude fields that are not needed.
*/
private Map<Integer, Field> sortedFieldMap;
/**
* Fields using the index attribute
*/
private Map<Integer, Field> indexFieldMap;
/**
* Fields to ignore
*/
private Map<String, Field> ignoreMap;
}

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

@ -2,6 +2,8 @@ package com.alibaba.excel.metadata;
import java.util.Locale;
import com.alibaba.excel.enums.CacheLocationEnum;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@ -32,6 +34,7 @@ public class GlobalConfiguration {
* used when formatting dates and numbers.
*/
private Locale locale;
/**
* Whether to use scientific Format.
*
@ -39,10 +42,18 @@ public class GlobalConfiguration {
*/
private Boolean useScientificFormat;
/**
* The cache used when parsing fields such as head.
*
* default is THREAD_LOCAL.
*/
private CacheLocationEnum filedCacheLocation;
public GlobalConfiguration() {
this.autoTrim = Boolean.TRUE;
this.use1904windowing = Boolean.FALSE;
this.locale = Locale.getDefault();
this.useScientificFormat = Boolean.FALSE;
this.filedCacheLocation = CacheLocationEnum.MEMORY;
}
}

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

@ -9,6 +9,8 @@ import java.util.TreeMap;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.enums.HeadKindEnum;
import com.alibaba.excel.metadata.ConfigurationHolder;
import com.alibaba.excel.metadata.FieldCache;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.Holder;
import com.alibaba.excel.util.ClassUtils;
@ -51,22 +53,17 @@ public class ExcelHeadProperty {
* Configuration header information
*/
private Map<Integer, Head> headMap;
/**
* Fields ignored
*/
private Map<String, Field> ignoreMap;
public ExcelHeadProperty(Holder holder, Class<?> headClazz, List<List<String>> head) {
public ExcelHeadProperty(ConfigurationHolder configurationHolder, Class<?> headClazz, List<List<String>> head) {
this.headClazz = headClazz;
headMap = new TreeMap<>();
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)) {
if (configurationHolder instanceof AbstractWriteHolder) {
if (((AbstractWriteHolder)configurationHolder).ignore(null, i)) {
continue;
}
}
@ -76,7 +73,7 @@ public class ExcelHeadProperty {
headKind = HeadKindEnum.STRING;
}
// convert headClazz to head
initColumnProperties(holder);
initColumnProperties(configurationHolder);
initHeadRowNumber();
if (LOGGER.isDebugEnabled()) {
@ -104,24 +101,15 @@ public class ExcelHeadProperty {
}
}
private void initColumnProperties(Holder holder) {
private void initColumnProperties(ConfigurationHolder configurationHolder) {
if (headClazz == null) {
return;
}
// Declared fields
Map<Integer, Field> sortedAllFieldMap = MapUtils.newTreeMap();
Map<Integer, Field> indexFieldMap = MapUtils.newTreeMap();
boolean needIgnore = (holder instanceof AbstractWriteHolder) && (
!CollectionUtils.isEmpty(((AbstractWriteHolder)holder).getExcludeColumnFieldNames()) || !CollectionUtils
.isEmpty(((AbstractWriteHolder)holder).getExcludeColumnIndexes()) || !CollectionUtils
.isEmpty(((AbstractWriteHolder)holder).getIncludeColumnFieldNames()) || !CollectionUtils
.isEmpty(((AbstractWriteHolder)holder).getIncludeColumnIndexes()));
ClassUtils.declaredFields(headClazz, sortedAllFieldMap, indexFieldMap, ignoreMap, needIgnore, holder);
FieldCache fieldCache = ClassUtils.declaredFields(headClazz, configurationHolder);
for (Map.Entry<Integer, Field> entry : sortedAllFieldMap.entrySet()) {
initOneColumnProperty(entry.getKey(), entry.getValue(), indexFieldMap.containsKey(entry.getKey()));
for (Map.Entry<Integer, Field> entry : fieldCache.getSortedFieldMap().entrySet()) {
initOneColumnProperty(entry.getKey(), entry.getValue(),
fieldCache.getIndexFieldMap().containsKey(entry.getKey()));
}
headKind = HeadKindEnum.CLASS;
}

3
easyexcel-core/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java

@ -149,7 +149,8 @@ public class ModelBuildEventListener implements IgnoreExceptionReadListener<Map<
ReadCellData<?> cellData = cellDataMap.get(index);
Object value = ConverterUtils.convertToJavaObject(cellData, head.getField(),
ClassUtils.declaredExcelContentProperty(dataMap, readSheetHolder.excelReadHeadProperty().getHeadClazz(),
fieldName), readSheetHolder.converterMap(), context, context.readRowHolder().getRowIndex(), index);
fieldName, readSheetHolder), readSheetHolder.converterMap(), context,
context.readRowHolder().getRowIndex(), index);
if (value != null) {
dataMap.put(fieldName, value);
}

5
easyexcel-core/src/main/java/com/alibaba/excel/read/metadata/property/ExcelReadHeadProperty.java

@ -2,6 +2,7 @@ package com.alibaba.excel.read.metadata.property;
import java.util.List;
import com.alibaba.excel.metadata.ConfigurationHolder;
import com.alibaba.excel.metadata.Holder;
import com.alibaba.excel.metadata.property.ExcelHeadProperty;
@ -12,7 +13,7 @@ import com.alibaba.excel.metadata.property.ExcelHeadProperty;
*/
public class ExcelReadHeadProperty extends ExcelHeadProperty {
public ExcelReadHeadProperty(Holder holder, Class headClazz, List<List<String>> head) {
super(holder, headClazz, head);
public ExcelReadHeadProperty(ConfigurationHolder configurationHolder, Class headClazz, List<List<String>> head) {
super(configurationHolder, headClazz, head);
}
}

435
easyexcel-core/src/main/java/com/alibaba/excel/util/ClassUtils.java

@ -14,6 +14,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
@ -24,7 +25,10 @@ import com.alibaba.excel.annotation.write.style.ContentFontStyle;
import com.alibaba.excel.annotation.write.style.ContentStyle;
import com.alibaba.excel.converters.AutoConverter;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CacheLocationEnum;
import com.alibaba.excel.exception.ExcelCommonException;
import com.alibaba.excel.metadata.ConfigurationHolder;
import com.alibaba.excel.metadata.FieldCache;
import com.alibaba.excel.metadata.Holder;
import com.alibaba.excel.metadata.property.DateTimeFormatProperty;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
@ -59,18 +63,38 @@ import org.springframework.util.CollectionUtils;
*/
public class ClassUtils {
public static final Map<Class<?>, FieldCache> FIELD_CACHE = new ConcurrentHashMap<>();
/**
* memory cache
*/
public static final ConcurrentHashMap<Class<?>, FieldCache> FIELD_CACHE = new ConcurrentHashMap<>();
/**
* thread local cahe
*/
private static final ThreadLocal<Map<Class<?>, FieldCache>> FIELD_THREAD_LOCAL = new ThreadLocal<>();
/**
* The cache configuration information for each of the class
*/
public static final Map<Class<?>, Map<String, ExcelContentProperty>> CLASS_CONTENT_CACHE
public static final ConcurrentHashMap<Class<?>, Map<String, ExcelContentProperty>> CLASS_CONTENT_CACHE
= new ConcurrentHashMap<>();
/**
* The cache configuration information for each of the class
*/
public static final Map<ContentPropertyKey, ExcelContentProperty> CONTENT_CACHE = new ConcurrentHashMap<>();
private static final ThreadLocal<Map<Class<?>, Map<String, ExcelContentProperty>>> CLASS_CONTENT_THREAD_LOCAL
= new ThreadLocal<>();
/**
* The cache configuration information for each of the class
*/
public static final ConcurrentHashMap<ContentPropertyKey, ExcelContentProperty> CONTENT_CACHE
= new ConcurrentHashMap<>();
/**
* The cache configuration information for each of the class
*/
private static final ThreadLocal<Map<ContentPropertyKey, ExcelContentProperty>> CONTENT_THREAD_LOCAL
= new ThreadLocal<>();
/**
* Calculate the configuration information for the class
@ -81,7 +105,7 @@ public class ClassUtils {
* @return
*/
public static ExcelContentProperty declaredExcelContentProperty(Map<?, ?> dataMap, Class<?> headClazz,
String fieldName) {
String fieldName, ConfigurationHolder configurationHolder) {
Class<?> clazz = null;
if (dataMap instanceof BeanMap) {
Object bean = ((BeanMap)dataMap).getBean();
@ -89,26 +113,49 @@ public class ClassUtils {
clazz = bean.getClass();
}
}
return getExcelContentProperty(clazz, headClazz, fieldName);
return getExcelContentProperty(clazz, headClazz, fieldName, configurationHolder);
}
private static ExcelContentProperty getExcelContentProperty(Class<?> clazz, Class<?> headClass, String fieldName) {
return CONTENT_CACHE.computeIfAbsent(buildKey(clazz, headClass, fieldName), key -> {
ExcelContentProperty excelContentProperty = Optional.ofNullable(declaredFieldContentMap(clazz))
.map(map -> map.get(fieldName))
.orElse(null);
ExcelContentProperty headExcelContentProperty = Optional.ofNullable(declaredFieldContentMap(headClass))
.map(map -> map.get(fieldName))
.orElse(null);
ExcelContentProperty combineExcelContentProperty = new ExcelContentProperty();
combineExcelContentProperty(combineExcelContentProperty, headExcelContentProperty);
if (clazz != headClass) {
combineExcelContentProperty(combineExcelContentProperty, excelContentProperty);
}
return combineExcelContentProperty;
});
private static ExcelContentProperty getExcelContentProperty(Class<?> clazz, Class<?> headClass, String fieldName,
ConfigurationHolder configurationHolder) {
switch (configurationHolder.globalConfiguration().getFiledCacheLocation()) {
case THREAD_LOCAL:
Map<ContentPropertyKey, ExcelContentProperty> contentCacheMap = CONTENT_THREAD_LOCAL.get();
if (contentCacheMap == null) {
contentCacheMap = MapUtils.newHashMap();
CONTENT_THREAD_LOCAL.set(contentCacheMap);
}
return contentCacheMap.computeIfAbsent(buildKey(clazz, headClass, fieldName), key -> {
return doGetExcelContentProperty(clazz, headClass, fieldName, configurationHolder);
});
case MEMORY:
return CONTENT_CACHE.computeIfAbsent(buildKey(clazz, headClass, fieldName), key -> {
return doGetExcelContentProperty(clazz, headClass, fieldName, configurationHolder);
});
case NONE:
return doGetExcelContentProperty(clazz, headClass, fieldName, configurationHolder);
default:
throw new UnsupportedOperationException("unsupported enum");
}
}
private static ExcelContentProperty doGetExcelContentProperty(Class<?> clazz, Class<?> headClass,
String fieldName, ConfigurationHolder configurationHolder) {
ExcelContentProperty excelContentProperty = Optional.ofNullable(
declaredFieldContentMap(clazz, configurationHolder))
.map(map -> map.get(fieldName))
.orElse(null);
ExcelContentProperty headExcelContentProperty = Optional.ofNullable(
declaredFieldContentMap(headClass, configurationHolder))
.map(map -> map.get(fieldName))
.orElse(null);
ExcelContentProperty combineExcelContentProperty = new ExcelContentProperty();
combineExcelContentProperty(combineExcelContentProperty, headExcelContentProperty);
if (clazz != headClass) {
combineExcelContentProperty(combineExcelContentProperty, excelContentProperty);
}
return combineExcelContentProperty;
}
public static void combineExcelContentProperty(ExcelContentProperty combineExcelContentProperty,
@ -140,182 +187,248 @@ public class ClassUtils {
return new ContentPropertyKey(clazz, headClass, fieldName);
}
private static Map<String, ExcelContentProperty> declaredFieldContentMap(Class<?> clazz) {
private static Map<String, ExcelContentProperty> declaredFieldContentMap(Class<?> clazz,
ConfigurationHolder configurationHolder) {
if (clazz == null) {
return null;
}
return CLASS_CONTENT_CACHE.computeIfAbsent(clazz, key -> {
List<Field> tempFieldList = new ArrayList<>();
Class<?> tempClass = clazz;
while (tempClass != null) {
Collections.addAll(tempFieldList, tempClass.getDeclaredFields());
// Get the parent class and give it to yourself
tempClass = tempClass.getSuperclass();
}
ContentStyle parentContentStyle = clazz.getAnnotation(ContentStyle.class);
ContentFontStyle parentContentFontStyle = clazz.getAnnotation(ContentFontStyle.class);
Map<String, ExcelContentProperty> fieldContentMap = MapUtils.newHashMapWithExpectedSize(
tempFieldList.size());
for (Field field : tempFieldList) {
ExcelContentProperty excelContentProperty = new ExcelContentProperty();
excelContentProperty.setField(field);
ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
if (excelProperty != null) {
Class<? extends Converter<?>> convertClazz = excelProperty.converter();
if (convertClazz != AutoConverter.class) {
try {
Converter<?> converter = convertClazz.getDeclaredConstructor().newInstance();
excelContentProperty.setConverter(converter);
} catch (Exception e) {
throw new ExcelCommonException(
"Can not instance custom converter:" + convertClazz.getName());
}
}
switch (configurationHolder.globalConfiguration().getFiledCacheLocation()) {
case THREAD_LOCAL:
Map<Class<?>, Map<String, ExcelContentProperty>> classContentCacheMap
= CLASS_CONTENT_THREAD_LOCAL.get();
if (classContentCacheMap == null) {
classContentCacheMap = MapUtils.newHashMap();
CLASS_CONTENT_THREAD_LOCAL.set(classContentCacheMap);
}
return classContentCacheMap.computeIfAbsent(clazz, key -> {
return doDeclaredFieldContentMap(clazz);
});
case MEMORY:
return CLASS_CONTENT_CACHE.computeIfAbsent(clazz, key -> {
return doDeclaredFieldContentMap(clazz);
});
case NONE:
return doDeclaredFieldContentMap(clazz);
default:
throw new UnsupportedOperationException("unsupported enum");
}
ContentStyle contentStyle = field.getAnnotation(ContentStyle.class);
if (contentStyle == null) {
contentStyle = parentContentStyle;
}
excelContentProperty.setContentStyleProperty(StyleProperty.build(contentStyle));
}
private static Map<String, ExcelContentProperty> doDeclaredFieldContentMap(Class<?> clazz) {
if (clazz == null) {
return null;
}
List<Field> tempFieldList = new ArrayList<>();
Class<?> tempClass = clazz;
while (tempClass != null) {
Collections.addAll(tempFieldList, tempClass.getDeclaredFields());
// Get the parent class and give it to yourself
tempClass = tempClass.getSuperclass();
}
ContentFontStyle contentFontStyle = field.getAnnotation(ContentFontStyle.class);
if (contentFontStyle == null) {
contentFontStyle = parentContentFontStyle;
ContentStyle parentContentStyle = clazz.getAnnotation(ContentStyle.class);
ContentFontStyle parentContentFontStyle = clazz.getAnnotation(ContentFontStyle.class);
Map<String, ExcelContentProperty> fieldContentMap = MapUtils.newHashMapWithExpectedSize(
tempFieldList.size());
for (Field field : tempFieldList) {
ExcelContentProperty excelContentProperty = new ExcelContentProperty();
excelContentProperty.setField(field);
ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
if (excelProperty != null) {
Class<? extends Converter<?>> convertClazz = excelProperty.converter();
if (convertClazz != AutoConverter.class) {
try {
Converter<?> converter = convertClazz.getDeclaredConstructor().newInstance();
excelContentProperty.setConverter(converter);
} catch (Exception e) {
throw new ExcelCommonException(
"Can not instance custom converter:" + convertClazz.getName());
}
}
excelContentProperty.setContentFontProperty(FontProperty.build(contentFontStyle));
}
excelContentProperty.setDateTimeFormatProperty(
DateTimeFormatProperty.build(field.getAnnotation(DateTimeFormat.class)));
excelContentProperty.setNumberFormatProperty(
NumberFormatProperty.build(field.getAnnotation(NumberFormat.class)));
ContentStyle contentStyle = field.getAnnotation(ContentStyle.class);
if (contentStyle == null) {
contentStyle = parentContentStyle;
}
excelContentProperty.setContentStyleProperty(StyleProperty.build(contentStyle));
fieldContentMap.put(field.getName(), excelContentProperty);
ContentFontStyle contentFontStyle = field.getAnnotation(ContentFontStyle.class);
if (contentFontStyle == null) {
contentFontStyle = parentContentFontStyle;
}
return fieldContentMap;
});
excelContentProperty.setContentFontProperty(FontProperty.build(contentFontStyle));
excelContentProperty.setDateTimeFormatProperty(
DateTimeFormatProperty.build(field.getAnnotation(DateTimeFormat.class)));
excelContentProperty.setNumberFormatProperty(
NumberFormatProperty.build(field.getAnnotation(NumberFormat.class)));
fieldContentMap.put(field.getName(), excelContentProperty);
}
return fieldContentMap;
}
/**
* Parsing field in the class
*
* @param clazz Need to parse the class
* @param sortedAllFieldMap Complete the map of sorts
* @param indexFieldMap Use the index to sort fields
* @param ignoreMap You want to ignore field map
* @param needIgnore If you want to ignore fields need to ignore
* @param holder holder
* @param clazz Need to parse the class
* @param needIgnore If you want to ignore fields need to ignore
* @param holder holder
* @param cacheLocation cache lcation
*/
public static void declaredFields(Class<?> clazz, Map<Integer, Field> sortedAllFieldMap,
Map<Integer, Field> indexFieldMap, Map<String, Field> ignoreMap, Boolean needIgnore, Holder holder) {
FieldCache fieldCache = declaredFields(clazz);
if (fieldCache == null) {
return;
public static FieldCache declaredFields(Class<?> clazz, ConfigurationHolder configurationHolder) {
switch (configurationHolder.globalConfiguration().getFiledCacheLocation()) {
case THREAD_LOCAL:
Map<Class<?>, FieldCache> fieldCacheMap = FIELD_THREAD_LOCAL.get();
if (fieldCacheMap == null) {
fieldCacheMap = MapUtils.newHashMap();
FIELD_THREAD_LOCAL.set(fieldCacheMap);
}
return fieldCacheMap.computeIfAbsent(clazz, key -> {
return doDeclaredFields(clazz, configurationHolder);
});
case MEMORY:
return FIELD_CACHE.computeIfAbsent(clazz, key -> {
return doDeclaredFields(clazz, configurationHolder);
});
case NONE:
return doDeclaredFields(clazz, configurationHolder);
default:
throw new UnsupportedOperationException("unsupported enum");
}
if (ignoreMap != null) {
ignoreMap.putAll(fieldCache.getIgnoreMap());
}
private static FieldCache doDeclaredFields(Class<?> clazz, ConfigurationHolder configurationHolder) {
List<Field> tempFieldList = new ArrayList<>();
Class<?> tempClass = clazz;
// When the parent class is null, it indicates that the parent class (Object class) has reached the top
// level.
while (tempClass != null) {
Collections.addAll(tempFieldList, tempClass.getDeclaredFields());
// Get the parent class and give it to yourself
tempClass = tempClass.getSuperclass();
}
Map<Integer, Field> tempIndexFieldMap = indexFieldMap;
if (tempIndexFieldMap == null) {
tempIndexFieldMap = MapUtils.newTreeMap();
// Screening of field
Map<Integer, List<Field>> orderFieldMap = new TreeMap<Integer, List<Field>>();
Map<Integer, Field> indexFieldMap = new TreeMap<Integer, Field>();
Map<String, Field> ignoreMap = new HashMap<String, Field>(16);
ExcelIgnoreUnannotated excelIgnoreUnannotated = clazz.getAnnotation(ExcelIgnoreUnannotated.class);
for (Field field : tempFieldList) {
declaredOneField(field, orderFieldMap, indexFieldMap, ignoreMap, excelIgnoreUnannotated);
}
tempIndexFieldMap.putAll(fieldCache.getIndexFieldMap());
Map<Integer, Field> sortedFieldMap = buildSortedAllFieldMap(orderFieldMap, indexFieldMap);
FieldCache fieldCache = new FieldCache(sortedFieldMap, indexFieldMap, ignoreMap);
Map<Integer, Field> originSortedAllFieldMap = fieldCache.getSortedAllFieldMap();
if (!needIgnore) {
sortedAllFieldMap.putAll(originSortedAllFieldMap);
return;
if (!(configurationHolder instanceof WriteHolder)) {
return fieldCache;
}
WriteHolder writeHolder = (WriteHolder)configurationHolder;
boolean needIgnore = !CollectionUtils.isEmpty(writeHolder.excludeColumnFieldNames())
|| !CollectionUtils.isEmpty(writeHolder.excludeColumnIndexes())
|| !CollectionUtils.isEmpty(writeHolder.includeColumnFieldNames())
|| !CollectionUtils.isEmpty(writeHolder.includeColumnIndexes());
if (!needIgnore) {
return fieldCache;
}
// ignore filed
Map<Integer, Field> tempSortedFieldMapp = MapUtils.newHashMap();
int index = 0;
for (Map.Entry<Integer, Field> entry : originSortedAllFieldMap.entrySet()) {
for (Map.Entry<Integer, Field> entry : sortedFieldMap.entrySet()) {
Integer key = entry.getKey();
Field field = entry.getValue();
// The current field needs to be ignored
if (((WriteHolder)holder).ignore(entry.getValue().getName(), entry.getKey())) {
if (writeHolder.ignore(entry.getValue().getName(), entry.getKey())) {
if (ignoreMap != null) {
ignoreMap.put(field.getName(), field);
}
tempIndexFieldMap.remove(index);
indexFieldMap.remove(index);
} else {
// Mandatory sorted fields
if (tempIndexFieldMap.containsKey(key)) {
sortedAllFieldMap.put(key, field);
if (indexFieldMap.containsKey(key)) {
tempSortedFieldMapp.put(key, field);
} else {
// Need to reorder automatically
// Check whether the current key is already in use
while (sortedAllFieldMap.containsKey(index)) {
while (tempSortedFieldMapp.containsKey(index)) {
index++;
}
sortedAllFieldMap.put(index++, field);
tempSortedFieldMapp.put(index++, field);
}
}
}
forceIndexIfNecessary(holder, sortedAllFieldMap);
fieldCache.setSortedFieldMap(tempSortedFieldMapp);
// resort field
resortField(writeHolder, fieldCache);
return fieldCache;
}
/**
* it only works when {@link AbstractWriteHolder#getIncludeColumnFieldNames()} has value
* and {@link AbstractWriteHolder#getForceIndex()} is true
* it only works when {@link WriteHolder#getIncludeColumnFieldNames()} or
* {@link WriteHolder#getIncludeColumnIndexes()} ()} has value
* and {@link WriteHolder#getSortByIncludeColumn()} ()} is true
**/
private static void forceIndexIfNecessary(Holder holder, Map<Integer, Field> sortedAllFieldMap) {
if (!(holder instanceof AbstractWriteHolder)) {
private static void resortField(WriteHolder writeHolder, FieldCache fieldCache) {
if (!writeHolder.sortByIncludeColumn()) {
return;
}
AbstractWriteHolder writeHolder = (AbstractWriteHolder)holder;
Collection<String> allCol = writeHolder.getIncludeColumnFieldNames();
if (!CollectionUtils.isEmpty(allCol) && writeHolder.getForceIndex() != null && writeHolder.getForceIndex()) {
Map<String, Integer> colIndexMap = MapUtils.newHashMap();
Iterator<String> iterator = allCol.iterator();
int colIndex = 0;
while (iterator.hasNext()) {
String col = iterator.next();
colIndexMap.put(col, colIndex);
colIndex++;
Map<Integer, Field> indexFieldMap = fieldCache.getIndexFieldMap();
Collection<String> includeColumnFieldNames = writeHolder.includeColumnFieldNames();
if (!CollectionUtils.isEmpty(includeColumnFieldNames)) {
// Field sorted map
Map<String, Integer> filedIndexMap = MapUtils.newHashMap();
int fieldIndex = 0;
for (String includeColumnFieldName : includeColumnFieldNames) {
filedIndexMap.put(includeColumnFieldName, fieldIndex++);
}
Map<Integer, Field> temp = MapUtils.newHashMap();
sortedAllFieldMap.forEach((index, field) -> {
Integer fieldIndex = colIndexMap.get(field.getName());
temp.put(fieldIndex, field);
// rebuild sortedFieldMap
Map<Integer, Field> tempSortedFieldMap = MapUtils.newHashMap();
fieldCache.getSortedFieldMap().forEach((index, field) -> {
Integer tempFieldIndex = filedIndexMap.get(field.getName());
if (tempFieldIndex != null) {
tempSortedFieldMap.put(tempFieldIndex, field);
// The user has redefined the ordering and the ordering of annotations needs to be invalidated
if (!tempFieldIndex.equals(index)) {
indexFieldMap.remove(index);
}
}
});
sortedAllFieldMap.clear();
sortedAllFieldMap.putAll(temp);
fieldCache.setSortedFieldMap(tempSortedFieldMap);
return;
}
}
public static void declaredFields(Class<?> clazz, Map<Integer, Field> sortedAllFieldMap, Boolean needIgnore,
WriteHolder writeHolder) {
declaredFields(clazz, sortedAllFieldMap, null, null, needIgnore, writeHolder);
}
Collection<Integer> includeColumnIndexes = writeHolder.includeColumnIndexes();
if (!CollectionUtils.isEmpty(includeColumnFieldNames)) {
// Index sorted map
Map<Integer, Integer> filedIndexMap = MapUtils.newHashMap();
int fieldIndex = 0;
for (Integer includeColumnIndexe : includeColumnIndexes) {
filedIndexMap.put(includeColumnIndexe, fieldIndex++);
}
private static FieldCache declaredFields(Class<?> clazz) {
if (clazz == null) {
return null;
// rebuild sortedFieldMap
Map<Integer, Field> tempSortedFieldMap = MapUtils.newHashMap();
fieldCache.getSortedFieldMap().forEach((index, field) -> {
Integer tempFieldIndex = filedIndexMap.get(index);
// The user has redefined the ordering and the ordering of annotations needs to be invalidated
if (tempFieldIndex != null) {
tempSortedFieldMap.put(tempFieldIndex, field);
}
});
fieldCache.setSortedFieldMap(tempSortedFieldMap);
}
return FIELD_CACHE.computeIfAbsent(clazz, key -> {
List<Field> tempFieldList = new ArrayList<>();
Class<?> tempClass = clazz;
// When the parent class is null, it indicates that the parent class (Object class) has reached the top
// level.
while (tempClass != null) {
Collections.addAll(tempFieldList, tempClass.getDeclaredFields());
// Get the parent class and give it to yourself
tempClass = tempClass.getSuperclass();
}
// Screening of field
Map<Integer, List<Field>> orderFieldMap = new TreeMap<Integer, List<Field>>();
Map<Integer, Field> indexFieldMap = new TreeMap<Integer, Field>();
Map<String, Field> ignoreMap = new HashMap<String, Field>(16);
ExcelIgnoreUnannotated excelIgnoreUnannotated = clazz.getAnnotation(ExcelIgnoreUnannotated.class);
for (Field field : tempFieldList) {
declaredOneField(field, orderFieldMap, indexFieldMap, ignoreMap, excelIgnoreUnannotated);
}
return new FieldCache(buildSortedAllFieldMap(orderFieldMap, indexFieldMap), indexFieldMap, ignoreMap);
});
}
private static Map<Integer, Field> buildSortedAllFieldMap(Map<Integer, List<Field>> orderFieldMap,
@ -380,32 +493,6 @@ public class ClassUtils {
orderFieldList.add(field);
}
private static class FieldCache {
private final Map<Integer, Field> sortedAllFieldMap;
private final Map<Integer, Field> indexFieldMap;
private final Map<String, Field> ignoreMap;
public FieldCache(Map<Integer, Field> sortedAllFieldMap, Map<Integer, Field> indexFieldMap,
Map<String, Field> ignoreMap) {
this.sortedAllFieldMap = sortedAllFieldMap;
this.indexFieldMap = indexFieldMap;
this.ignoreMap = ignoreMap;
}
public Map<Integer, Field> getSortedAllFieldMap() {
return sortedAllFieldMap;
}
public Map<Integer, Field> getIndexFieldMap() {
return indexFieldMap;
}
public Map<String, Field> getIgnoreMap() {
return ignoreMap;
}
}
/**
* <p>Gets a {@code List} of all interfaces implemented by the given
* class and its superclasses.</p>
@ -459,4 +546,10 @@ public class ClassUtils {
private Class<?> headClass;
private String fieldName;
}
public static void removeThreadLocalCache() {
FIELD_THREAD_LOCAL.remove();
CLASS_CONTENT_THREAD_LOCAL.remove();
CONTENT_THREAD_LOCAL.remove();
}
}

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

@ -122,11 +122,12 @@ public abstract class AbstractExcelWriterParameterBuilder<T extends AbstractExce
}
/**
* head index use {@link this#includeColumnFiledNames} sort
* useless if not set {@link this#includeColumnFiledNames}
* Data will be sorted according to {@link #includeColumnFieldNames} or {@link #includeColumnIndexes}.
*
* default is false.
**/
public T forceIndex(Boolean force) {
parameter().setForceIndex(force);
public T sortByIncludeColumn(Boolean sortByIncludeColumn) {
parameter().setSortByIncludeColumn(sortByIncludeColumn);
return self();
}
}

29
easyexcel-core/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java

@ -10,6 +10,7 @@ import java.util.TreeMap;
import com.alibaba.excel.context.WriteContext;
import com.alibaba.excel.enums.HeadKindEnum;
import com.alibaba.excel.metadata.FieldCache;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.util.BeanMapUtils;
@ -50,18 +51,15 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor {
if (writeSheetHolder.isNew() && !writeSheetHolder.getExcelWriteHeadProperty().hasHead()) {
newRowIndex += writeContext.currentWriteHolder().relativeHeadRowIndex();
}
// BeanMap is out of order, so use sortedAllFieldMap
Map<Integer, Field> sortedAllFieldMap = new TreeMap<>();
int relativeRowIndex = 0;
for (Object oneRowData : data) {
int lastRowIndex = relativeRowIndex + newRowIndex;
addOneRowOfDataToExcel(oneRowData, lastRowIndex, relativeRowIndex, sortedAllFieldMap);
addOneRowOfDataToExcel(oneRowData, lastRowIndex, relativeRowIndex);
relativeRowIndex++;
}
}
private void addOneRowOfDataToExcel(Object oneRowData, int rowIndex, int relativeRowIndex,
Map<Integer, Field> sortedAllFieldMap) {
private void addOneRowOfDataToExcel(Object oneRowData, int rowIndex, int relativeRowIndex) {
if (oneRowData == null) {
return;
}
@ -79,7 +77,7 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor {
} else if (oneRowData instanceof Map) {
addBasicTypeToExcel(new MapRowData((Map<Integer, ?>)oneRowData), row, rowIndex, relativeRowIndex);
} else {
addJavaObjectToExcel(oneRowData, row, rowIndex, relativeRowIndex, sortedAllFieldMap);
addJavaObjectToExcel(oneRowData, row, rowIndex, relativeRowIndex);
}
WriteHandlerUtils.afterRowDispose(rowWriteHandlerContext);
@ -119,7 +117,7 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor {
int dataIndex, int columnIndex) {
ExcelContentProperty excelContentProperty = ClassUtils.declaredExcelContentProperty(null,
writeContext.currentWriteHolder().excelWriteHeadProperty().getHeadClazz(),
head == null ? null : head.getFieldName());
head == null ? null : head.getFieldName(), writeContext.currentWriteHolder());
CellWriteHandlerContext cellWriteHandlerContext = WriteHandlerUtils.createCellWriteHandlerContext(writeContext,
row, rowIndex, head, columnIndex, relativeRowIndex, Boolean.FALSE, excelContentProperty);
@ -138,8 +136,7 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor {
WriteHandlerUtils.afterCellDispose(cellWriteHandlerContext);
}
private void addJavaObjectToExcel(Object oneRowData, Row row, int rowIndex, int relativeRowIndex,
Map<Integer, Field> sortedAllFieldMap) {
private void addJavaObjectToExcel(Object oneRowData, Row row, int rowIndex, int relativeRowIndex) {
WriteHolder currentWriteHolder = writeContext.currentWriteHolder();
BeanMap beanMap = BeanMapUtils.create(oneRowData);
// Bean the contains of the Map Key method with poor performance,So to create a keySet here
@ -158,7 +155,7 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor {
}
ExcelContentProperty excelContentProperty = ClassUtils.declaredExcelContentProperty(beanMap,
currentWriteHolder.excelWriteHeadProperty().getHeadClazz(), name);
currentWriteHolder.excelWriteHeadProperty().getHeadClazz(), name, currentWriteHolder);
CellWriteHandlerContext cellWriteHandlerContext = WriteHandlerUtils.createCellWriteHandlerContext(
writeContext, row, rowIndex, head, columnIndex, relativeRowIndex, Boolean.FALSE,
excelContentProperty);
@ -185,19 +182,17 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor {
}
maxCellIndex++;
Map<String, Field> ignoreMap = writeContext.currentWriteHolder().excelWriteHeadProperty().getIgnoreMap();
initSortedAllFieldMapFieldList(oneRowData.getClass(), sortedAllFieldMap);
for (Map.Entry<Integer, Field> entry : sortedAllFieldMap.entrySet()) {
FieldCache fieldCache = ClassUtils.declaredFields(oneRowData.getClass(), writeContext.currentWriteHolder());
for (Map.Entry<Integer, Field> entry : fieldCache.getSortedFieldMap().entrySet()) {
Field field = entry.getValue();
String fieldName = FieldUtils.resolveCglibFieldName(field);
boolean uselessData = !beanKeySet.contains(fieldName) || beanMapHandledSet.contains(fieldName)
|| ignoreMap.containsKey(fieldName);
boolean uselessData = !beanKeySet.contains(fieldName) || beanMapHandledSet.contains(fieldName);
if (uselessData) {
continue;
}
Object value = beanMap.get(fieldName);
ExcelContentProperty excelContentProperty = ClassUtils.declaredExcelContentProperty(beanMap,
currentWriteHolder.excelWriteHeadProperty().getHeadClazz(), fieldName);
currentWriteHolder.excelWriteHeadProperty().getHeadClazz(), fieldName, currentWriteHolder);
CellWriteHandlerContext cellWriteHandlerContext = WriteHandlerUtils.createCellWriteHandlerContext(
writeContext, row, rowIndex, null, maxCellIndex, relativeRowIndex, Boolean.FALSE, excelContentProperty);
WriteHandlerUtils.beforeCellCreate(cellWriteHandlerContext);
@ -229,7 +224,7 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor {
.isEmpty(writeSheetHolder.getExcludeColumnIndexes()) || !CollectionUtils
.isEmpty(writeSheetHolder.getIncludeColumnFieldNames()) || !CollectionUtils
.isEmpty(writeSheetHolder.getIncludeColumnIndexes());
ClassUtils.declaredFields(clazz, sortedAllFieldMap, needIgnore, writeSheetHolder);
ClassUtils.declaredFields(clazz, writeSheetHolder);
}
}

8
easyexcel-core/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java

@ -37,7 +37,9 @@ import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.collections4.CollectionUtils;
import com.alibaba.excel.util.PoiUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
@ -215,7 +217,8 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
}
Object value = dataMap.get(variable);
ExcelContentProperty excelContentProperty = ClassUtils.declaredExcelContentProperty(dataMap,
writeContext.currentWriteHolder().excelWriteHeadProperty().getHeadClazz(), variable);
writeContext.currentWriteHolder().excelWriteHeadProperty().getHeadClazz(), variable,
writeContext.currentWriteHolder());
cellWriteHandlerContext.setExcelContentProperty(excelContentProperty);
createCell(analysisCell, fillConfig, cellWriteHandlerContext, rowWriteHandlerContext);
@ -249,7 +252,8 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
}
Object value = dataMap.get(variable);
ExcelContentProperty excelContentProperty = ClassUtils.declaredExcelContentProperty(dataMap,
writeContext.currentWriteHolder().excelWriteHeadProperty().getHeadClazz(), variable);
writeContext.currentWriteHolder().excelWriteHeadProperty().getHeadClazz(), variable,
writeContext.currentWriteHolder());
cellWriteHandlerContext.setOriginalValue(value);
cellWriteHandlerContext.setOriginalFieldClass(FieldUtils.getFieldClass(dataMap, variable, value));
cellWriteHandlerContext.setExcelContentProperty(excelContentProperty);

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

@ -56,8 +56,11 @@ public class WriteBasicParameter extends BasicParameter {
* Only output the custom columns.
*/
private Collection<String> includeColumnFieldNames;
/**
* head sorted use includeColumnFieldNames sort
* Data will be sorted according to {@link #includeColumnFieldNames} or {@link #includeColumnIndexes}.
*
* default is false.
*/
private Boolean forceIndex;
private Boolean sortByIncludeColumn;
}

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

@ -14,6 +14,7 @@ import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.converters.ConverterKeyBuild;
import com.alibaba.excel.converters.DefaultConverterLoader;
import com.alibaba.excel.enums.HeadKindEnum;
import com.alibaba.excel.enums.HolderEnum;
import com.alibaba.excel.event.NotRepeatExecutor;
import com.alibaba.excel.metadata.AbstractHolder;
import com.alibaba.excel.metadata.Head;
@ -94,10 +95,14 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
* Only output the custom columns.
*/
private Collection<String> includeColumnFieldNames;
/**
* head sorted use {@link #includeColumnFieldNames} sort
* Data will be sorted according to {@link #includeColumnFieldNames} or {@link #includeColumnIndexes}.
*
* default is false.
*/
private Boolean forceIndex;
private Boolean sortByIncludeColumn;
/**
* Write handler
*/
@ -197,11 +202,17 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
} else {
this.includeColumnFieldNames = writeBasicParameter.getIncludeColumnFieldNames();
}
if (writeBasicParameter.getForceIndex() == null && parentAbstractWriteHolder != null) {
this.forceIndex = parentAbstractWriteHolder.getForceIndex();
if (writeBasicParameter.getSortByIncludeColumn() == null) {
if (parentAbstractWriteHolder == null) {
this.sortByIncludeColumn = Boolean.FALSE;
} else {
this.sortByIncludeColumn = parentAbstractWriteHolder.getSortByIncludeColumn();
}
} else {
this.forceIndex = writeBasicParameter.getForceIndex();
this.sortByIncludeColumn = writeBasicParameter.getSortByIncludeColumn();
}
if (writeBasicParameter.getIncludeColumnIndexes() == null && parentAbstractWriteHolder != null) {
this.includeColumnIndexes = parentAbstractWriteHolder.getIncludeColumnIndexes();
} else {
@ -488,4 +499,28 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ
return getAutomaticMergeHead();
}
@Override
public boolean sortByIncludeColumn() {
return getSortByIncludeColumn();
}
@Override
public Collection<Integer> includeColumnIndexes() {
return getIncludeColumnIndexes();
}
@Override
public Collection<String> includeColumnFieldNames() {
return getIncludeColumnFieldNames();
}
@Override
public Collection<Integer> excludeColumnIndexes() {
return getExcludeColumnIndexes();
}
@Override
public Collection<String> excludeColumnFieldNames() {
return getExcludeColumnFieldNames();
}
}

29
easyexcel-core/src/main/java/com/alibaba/excel/write/metadata/holder/WriteHolder.java

@ -1,10 +1,11 @@
package com.alibaba.excel.write.metadata.holder;
import java.util.Collection;
import com.alibaba.excel.metadata.ConfigurationHolder;
import com.alibaba.excel.write.property.ExcelWriteHeadProperty;
/**
*
* Get the corresponding Holder
*
* @author Jiaju Zhuang
@ -46,4 +47,30 @@ public interface WriteHolder extends ConfigurationHolder {
* @return
*/
int relativeHeadRowIndex();
/**
* Data will be sorted according to {@link #includeColumnFieldNames} or {@link #includeColumnIndexes}.
*
* default is false.
*/
boolean sortByIncludeColumn();
/**
* Only output the custom columns.
*/
Collection<Integer> includeColumnIndexes();
/**
* Only output the custom columns.
*/
Collection<String> includeColumnFieldNames();
/**
* Ignore the custom columns.
*/
Collection<Integer> excludeColumnIndexes();
/**
* Ignore the custom columns.
*/
Collection<String> excludeColumnFieldNames();
}

1
easyexcel-core/src/main/java/com/alibaba/excel/write/metadata/holder/WriteWorkbookHolder.java

@ -11,6 +11,7 @@ import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.excel.enums.CacheLocationEnum;
import com.alibaba.excel.enums.HolderEnum;
import com.alibaba.excel.exception.ExcelGenerateException;
import com.alibaba.excel.metadata.data.DataFormatData;

5
easyexcel-core/src/main/java/com/alibaba/excel/write/property/ExcelWriteHeadProperty.java

@ -16,6 +16,7 @@ import com.alibaba.excel.annotation.write.style.HeadStyle;
import com.alibaba.excel.annotation.write.style.OnceAbsoluteMerge;
import com.alibaba.excel.enums.HeadKindEnum;
import com.alibaba.excel.metadata.CellRange;
import com.alibaba.excel.metadata.ConfigurationHolder;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.Holder;
import com.alibaba.excel.metadata.property.ColumnWidthProperty;
@ -44,8 +45,8 @@ public class ExcelWriteHeadProperty extends ExcelHeadProperty {
private RowHeightProperty contentRowHeightProperty;
private OnceAbsoluteMergeProperty onceAbsoluteMergeProperty;
public ExcelWriteHeadProperty(Holder holder, Class<?> headClazz, List<List<String>> head) {
super(holder, headClazz, head);
public ExcelWriteHeadProperty(ConfigurationHolder configurationHolder, Class<?> headClazz, List<List<String>> head) {
super(configurationHolder, headClazz, head);
if (getHeadKind() != HeadKindEnum.CLASS) {
return;
}

14
easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/excludeorinclude/ExcludeOrIncludeDataTest.java

@ -34,9 +34,9 @@ public class ExcludeOrIncludeDataTest {
private static File includeFieldName07;
private static File includeFieldName03;
private static File includeFieldNameCsv;
private static File includeFieldNameForceIndex07;
private static File includeFieldNameForceIndex03;
private static File includeFieldNameForceIndexCsv;
private static File includeFieldNameSort07;
private static File includeFieldNameSort03;
private static File includeFieldNameSortCsv;
@BeforeClass
public static void init() {
@ -52,9 +52,9 @@ public class ExcludeOrIncludeDataTest {
includeFieldName07 = TestFileUtil.createNewFile("includeFieldName.xlsx");
includeFieldName03 = TestFileUtil.createNewFile("includeFieldName.xls");
includeFieldNameCsv = TestFileUtil.createNewFile("includeFieldName.csv");
includeFieldNameForceIndex07 = TestFileUtil.createNewFile("includeFieldNameForceIndex.xlsx");
includeFieldNameForceIndex03 = TestFileUtil.createNewFile("includeFieldNameForceIndex.xls");
includeFieldNameForceIndexCsv = TestFileUtil.createNewFile("includeFieldNameForceIndex.csv");
includeFieldNameSort07 = TestFileUtil.createNewFile("includeFieldNameSort.xlsx");
includeFieldNameSort03 = TestFileUtil.createNewFile("includeFieldNameSort.xls");
includeFieldNameSortCsv = TestFileUtil.createNewFile("includeFieldNameSort.csv");
}
@Test
@ -197,7 +197,7 @@ public class ExcludeOrIncludeDataTest {
includeColumnFieldNames.add("column3");
includeColumnFieldNames.add("column2");
EasyExcel.write(file, ExcludeOrIncludeData.class).includeColumnFieldNames(includeColumnFieldNames)
.forceIndex(true).sheet().doWrite(data());
.sortByIncludeColumn(true).sheet().doWrite(data());
List<Map<Integer, String>> dataMap = EasyExcel.read(file).sheet().doReadSync();
Assert.assertEquals(1, dataMap.size());
Map<Integer, String> record = dataMap.get(0);

5
update.md

@ -5,7 +5,10 @@
* xlsx存在隐藏字符时需要忽略,确保和展示看到的一样
* 新增`commons-io` 2.11.0 包
* 在`easyexcel-parent` 包中移除测试包的`dependencyManagement`
* 删除`org.apache.poi.hssf.usermodel.PoiUtils.java`, 使用反射获取 [Issue #2804](https://github.com/alibaba/easyexcel/issues/2804)
* 删除`org.apache.poi.hssf.usermodel.PoiUtils.java`,
使用反射获取 [Issue #2804](https://github.com/alibaba/easyexcel/issues/2804)
* 默认对象反射缓存改成`ThreadLocal`,并支持设置 [Issue #2792](https://github.com/alibaba/easyexcel/issues/2792)
* 支持根据`includeColumnIndexes`和`includeColumnFieldNames`排序 [Issue #2697](https://github.com/alibaba/easyexcel/issues/2697)
# 3.2.1

Loading…
Cancel
Save