项目场景:
提示:这里简述项目相关背景:

(图片来源网络,侵删)
例如:项目场景: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 fieldList) { WriteHolder currentWriteHolder = writeContext.currentWriteHolder(); #### 重点BeanMap对象转化引发的问题 BeanMap beanMap = BeanMap.create(oneRowData); Set beanMapHandledSet = new HashSet(); int cellIndex = 0; // If it's a class it needs to be cast by type if (HeadKindEnum.CLASS.equals(writeContext.currentWriteHolder().excelWriteHeadProperty().getHeadKind())) { Map headMap = writeContext.currentWriteHolder().excelWriteHeadProperty().getHeadMap(); Map contentPropertyMap = writeContext.currentWriteHolder().excelWriteHeadProperty().getContentPropertyMap(); for (Map.Entry 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 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 ,结果“误伤”了我们这种场景。
解决方案:
最简单的办法属性不用单字母