- 当使用自定义头时,如果使用ExcelWriterSheetBuilder指定的excludeColumnFiledNames是无效的,但是使用ExcelWriterBuilder是有效的
- 当类的属性被指定了 index,但是又被配置为忽略字段时,会导致实际生产的 Excel 列后移,感觉这里应该由顺位索引列往前补位比较合理
[alibaba/easyexcel]修复当自定义 header 时,在 writeSheet 对象上指定字段名忽略不生效的问题 & 修复当属性被忽略时,会导致后续列后移,excel多了空白列的问题
回答
非常感谢您的pr 格式化 有问题 到入包不允许出现 *
- 问题没听懂 也没看清楚改了啥
- index 代表定位 就按照位置走。order代表排序 order会自动偏移。
@zhuangjiaju
抱歉,之前没有描述清楚。
第二个问题:当导出的类属性被指定为忽略字段时,会导致后续的列有多少个就会产生多少个空行。
@Data
public class IndexData {
@ExcelProperty(value = "字符串标题", index = 0)
private String string;
@ExcelProperty(value = "日期标题", index = 1)
private Date date;
/**
* 这里设置3 会导致第二列空的
*/
@ExcelProperty(value = "数字标题", index = 2)
private Double doubleData;
}
测试结果
当我导出类 IndexData 时,如果我指定忽略了 index 为 0 的属性,会导致生成 3 列空白列。
效果图如下:
测试代码:@Ignore
public class WriteTest1 {
@Test
public void indexWrite() {
String fileName = TestFileUtil.getPath() + "indexWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, IndexData.class)
.sheet("模板")
.excludeColumnIndexes(Collections.singleton(0))
.doWrite(indexData());
}
private List<IndexData> indexData() {
List<IndexData> list = new ArrayList<IndexData>();
for (int i = 0; i < 10; i++) {
IndexData data = new IndexData();
data.setString("字符串" + i);
data.setDate(new Date());
data.setDoubleData(0.56);
list.add(data);
}
return list;
}
}
修改逻辑
此 PR 将逻辑调整为,当属性被忽略时,用户指定的角标位应往前移动,例如 IndexData 中的 属性 date对应的 index 为 1,在 excel 中位于第二列。 但是在使用时,如果忽略了 index 0,则实际生成时,doubleData 的 index 应该进一,在生成的 excel 中应该位于第一列才比较符合。
同时,如果用户指定角标不连续产生的空行,会进行保留。比如用户只指定了 index 0 和 index 2,则实际生成时,会导致第二列为空列
主要是 使用 ExcelWriterBuilder 进行生成 excel 时,可以通过ExcelWriterBuilder#excludeColumnFiledNames 来进行列的排除, 但当我使用 ExcelWriterSheetBuilder 进行生成时,ExcelWriterSheetBuilder#excludeColumnFiledNames方法是不生效的。
测试对象@Data
public class IndexData {
@ExcelProperty(value = "字符串标题", index = 0)
private String string;
@ExcelProperty(value = "日期标题", index = 1)
private Date date;
@ExcelProperty(value = "数字标题", index = 2)
private Double doubleData;
}
测试代码:
/**
* 自定义头信息下的列属性忽略测试
*/
@Test
public void ignoreTest() {
// 文件名
String fileName = TestFileUtil.getPath() + "indexWrite" + System.currentTimeMillis() + ".xlsx";
// 忽略列属性
Set<String> excludeColumnFiledNames = Collections.singleton("string");
// 构建 excelWrite 对象
ExcelWriterBuilder writerBuilder = EasyExcel.write().file(fileName);
// 注意:在 excelWrite 对象中指定忽略的列属性是可以生效的
// 1. writerBuilder.excludeColumnFiledNames(excludeColumnFiledNames);
ExcelWriter writer = writerBuilder.build();
// 构建 writeSheet 对象
ExcelWriterSheetBuilder sheetBuilder = EasyExcel.writerSheet("sheet-1");
// 自定义头信息
sheetBuilder.head(head());
// 2. 这里指定忽略列属性不生效
sheetBuilder.excludeColumnFiledNames(excludeColumnFiledNames);
WriteSheet writeSheet = sheetBuilder.build();
// 写入 excel
writer.write(indexData(), writeSheet);
writer.finish();
}
private List<IndexData> indexData() {
List<IndexData> list = new ArrayList<IndexData>();
for (int i = 0; i < 10; i++) {
IndexData data = new IndexData();
data.setString("字符串" + i);
data.setDate(new Date());
data.setDoubleData(0.56);
list.add(data);
}
return list;
}
private List<List<String>> head() {
List<List<String>> list = new ArrayList<List<String>>();
List<String> head1 = new ArrayList<String>();
head1.add("数字1" + System.currentTimeMillis());
List<String> head2 = new ArrayList<String>();
head2.add("日期1" + System.currentTimeMillis());
list.add(head1);
list.add(head2);
return list;
}
生成结果:
可以看到,明明已经指定了,string
属性生成时需要进行忽略,但是却没有效果
在 com.alibaba.excel.write.executor.ExcelWriteAddExecutor#initSortedAllFiledMapFieldList 方法中,进行了字段排序和忽略的控制,但是判断是否需要忽略时,写死了获取的 WriteHolder 是 WorkbookHolder,所以当我们使用 SheetWrite 进行指定忽略时就会失效。
private void initSortedAllFiledMapFieldList(Class clazz, Map<Integer, Field> sortedAllFiledMap) {
if (!sortedAllFiledMap.isEmpty()) {
return;
}
WriteWorkbookHolder writeWorkbookHolder = writeContext.writeWorkbookHolder();
boolean needIgnore =
!CollectionUtils.isEmpty(writeWorkbookHolder.getExcludeColumnFiledNames()) || !CollectionUtils
.isEmpty(writeWorkbookHolder.getExcludeColumnIndexes()) || !CollectionUtils
.isEmpty(writeWorkbookHolder.getIncludeColumnFiledNames()) || !CollectionUtils
.isEmpty(writeWorkbookHolder.getIncludeColumnIndexes());
ClassUtils.declaredFields(clazz, sortedAllFiledMap,
writeWorkbookHolder.getWriteWorkbook().getConvertAllFiled(), needIgnore, writeWorkbookHolder);
}
修改方案:
首先获取的 WriteHolder 修改为 currentWriteHolder(),这样就可以在使用 SheetWriter 的之后正确获取到该对象。 再参考 com.alibaba.excel.metadata.property.ExcelHeadProperty#initColumnProperties 的方法,将 holder 强转为 AbstractWriteHolder 以便判断是否需要进行属性的忽略
private void initSortedAllFiledMapFieldList(Class clazz, Map<Integer, Field> sortedAllFiledMap) {
if (!sortedAllFiledMap.isEmpty()) {
return;
}
// 获取当前的使用的 holder
WriteHolder holder = writeContext.currentWriteHolder();
boolean needIgnore = (holder instanceof AbstractWriteHolder) && (
!CollectionUtils.isEmpty(((AbstractWriteHolder) holder).getExcludeColumnFiledNames()) || !CollectionUtils
.isEmpty(((AbstractWriteHolder) holder).getExcludeColumnIndexes()) || !CollectionUtils
.isEmpty(((AbstractWriteHolder) holder).getIncludeColumnFiledNames()) || !CollectionUtils
.isEmpty(((AbstractWriteHolder) holder).getIncludeColumnIndexes()));
ClassUtils.declaredFields(clazz, sortedAllFiledMap,
writeContext.writeWorkbookHolder().getWriteWorkbook().getConvertAllFiled(), needIgnore, holder);
}
@zhuangjiaju 这个 pr 有考虑合并吗
oK