项目场景:
提示:这里简述项目相关背景:
例如:项目场景:easyexcel 导出属性名单字母小写导出excel内容为空
问题描述
例如:easyexcel 导出属性名单字母小写引发的问题
@ExcelProperty(value = "T+30")
@ColumnWidth(30)
private Integer tPlus30; // 单字母属性,有数据值但是写excel 为空
原因分析:
例如:`net.sf.cglib.beans.BeanMap 属性名引发的问题
源码
private void addJavaObjectToExcel(Object oneRowData, Row row, int relativeRowIndex, List<Field> fieldList) {
WriteHolder currentWriteHolder = writeContext.currentWriteHolder();
#### 重点BeanMap对象转化引发的问题
BeanMap beanMap = BeanMap.create(oneRowData);
Set<String> beanMapHandledSet = new HashSet<String>();
int cellIndex = 0;
// If it's a class it needs to be cast by type
if (HeadKindEnum.CLASS.equals(writeContext.currentWriteHolder().excelWriteHeadProperty().getHeadKind())) {
Map<Integer, Head> headMap = writeContext.currentWriteHolder().excelWriteHeadProperty().getHeadMap();
Map<Integer, ExcelContentProperty> contentPropertyMap =
writeContext.currentWriteHolder().excelWriteHeadProperty().getContentPropertyMap();
for (Map.Entry<Integer, ExcelContentProperty> entry : contentPropertyMap.entrySet()) {
cellIndex = entry.getKey();
ExcelContentProperty excelContentProperty = entry.getValue();
String name = excelContentProperty.getField().getName();
if (writeContext.currentWriteHolder().ignore(name, cellIndex)) {
continue;
}
if (!beanMap.containsKey(name)) {
continue;
}
Head head = headMap.get(cellIndex);
WriteHandlerUtils.beforeCellCreate(writeContext, row, head, cellIndex, relativeRowIndex, Boolean.FALSE);
Cell cell = WorkBookUtil.createCell(row, cellIndex);
WriteHandlerUtils.afterCellCreate(writeContext, cell, head, relativeRowIndex, Boolean.FALSE);
Object value = beanMap.get(name);
CellData cellData = converterAndSet(currentWriteHolder, excelContentProperty.getField().getType(), cell,
value, excelContentProperty, head, relativeRowIndex);
WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, head, relativeRowIndex, Boolean.FALSE);
beanMapHandledSet.add(name);
}
}
// Finish
if (beanMapHandledSet.size() == beanMap.size()) {
return;
}
if (cellIndex != 0) {
cellIndex++;
}
Map<String, Field> ignoreMap = writeContext.currentWriteHolder().excelWriteHeadProperty().getIgnoreMap();
initFieldList(oneRowData.getClass(), fieldList);
for (Field field : fieldList) {
String filedName = field.getName();
boolean uselessData = !beanMap.containsKey(filedName) || beanMapHandledSet.contains(filedName)
|| ignoreMap.containsKey(filedName) || writeContext.currentWriteHolder().ignore(filedName, cellIndex);
if (uselessData) {
cellIndex++;
continue;
}
Object value = beanMap.get(filedName);
WriteHandlerUtils.beforeCellCreate(writeContext, row, null, cellIndex, relativeRowIndex, Boolean.FALSE);
Cell cell = WorkBookUtil.createCell(row, cellIndex++);
WriteHandlerUtils.afterCellCreate(writeContext, cell, null, relativeRowIndex, Boolean.FALSE);
CellData cellData = converterAndSet(currentWriteHolder, value == null ? null : value.getClass(), cell,
value, null, null, relativeRowIndex);
WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, null, relativeRowIndex, Boolean.FALSE);
}
}
注意:commons-beanutils 的 BeanMap 和 cglib 一样的问题,虽然类型没问题但是属性名还是不对。
原因:
调试一下就会发现,问题出在 BeanInfo 里面 PropertyDescriptor 的 name 不正确。
java.beans.Introspector#getBeanInfo() 中
经过分析会发现 java.beans.Introspector#getTargetPropertyInfo 方法是字段解析的关键
不管get或者set 属性会自动截取3
然后去构造 PropertyDescriptor:
PropertyDescriptor(Class<?> bean, String base, Method read, Method write) throws IntrospectionException {
if (bean == null) {
throw new IntrospectionException("Target Bean class is null");
}
setClass0(bean);
setName(Introspector.decapitalize(base));
setReadMethod(read);
setWriteMethod(write);
this.baseName = base;
}
Introspector.decapitalize(base) 方法:
从代码中我们可以看出 (1) 当 name 的长度 > 1,且第一个字符和第二个字符都大写时,直接返回参数作为PropertyDescriptor name。 (2) 否则将 name 转为首字母小写. 这种处理本意是为了不让属性为类似 URL 这种缩略词转为 uRL ,结果“误伤”了我们这种场景。
解决方案:
最简单的办法属性不用单字母