easypoi导出--深度解析为什么,数字类型列的单元格不能合并不能为空
问题一:数字类型列的单元格不能合并
easypoi导出时,给数字格式的列做纵向合并,前期发现:数字格式进行合并会报错,想要进行单元格合并的话单元格必须是字符串格式。
经过对源码的分析最终找到:PoiMergeCellUtil 这个类里的mergeCells 这个方法,
在这个方法中有一句代码:
String text = row.getCell(index).getStringCellValue();
这个不可以获取数值类型的单元格的数据,所以报错。继续观察发现:在“ getStringCellValue”这方法所在的接口中还有一个方法:
double getNumericCellValue();
我个人觉得可以在源码中加一个判断,从而使用“getNumericCellValue”这个方法,以达到数值单元格合并的效果。至于为什么easypoi没有这么做,因为没有更多文档以及个人理解问题的原因,我就不得而知了
mergeCells 方法的源码:
public static void mergeCells(Sheet sheet, Map<Integer, int[]> mergeMap, int startRow, int endRow) {
Map<Integer, MergeEntity> mergeDataMap = new HashMap();
if (mergeMap.size() != 0) {
Set<Integer> sets = mergeMap.keySet();
label55:
for(int i = startRow; i <= endRow; ++i) {
Row row = sheet.getRow(i);
Iterator var9 = sets.iterator();
while(true) {
while(true) {
if (!var9.hasNext()) {
continue label55;
}
Integer index = (Integer)var9.next();
if (row != null && row.getCell(index) != null) {
/**
* 这个getStringCellValue 方法不能获取数值类型的单元格的数据。所以会报错
*/
String text = row.getCell(index).getStringCellValue();
if (StringUtils.isNotEmpty(text)) {
hanlderMergeCells(index, i, text, mergeDataMap, sheet, row.getCell(index), (int[])mergeMap.get(index));
} else {
mergeCellOrContinue(index, mergeDataMap, sheet);
}
} else if (mergeDataMap.get(index) != null && ((MergeEntity)mergeDataMap.get(index)).getEndRow() == 0) {
((MergeEntity)mergeDataMap.get(index)).setEndRow(i - 1);
}
}
}
}
if (mergeDataMap.size() > 0) {
Iterator var11 = mergeDataMap.keySet().iterator();
while(var11.hasNext()) {
Integer index = (Integer)var11.next();
if (((MergeEntity)mergeDataMap.get(index)).getEndRow() > ((MergeEntity)mergeDataMap.get(index)).getStartRow()) {
sheet.addMergedRegion(new CellRangeAddress(((MergeEntity)mergeDataMap.get(index)).getStartRow(), ((MergeEntity)mergeDataMap.get(index)).getEndRow(), index, index));
}
}
}
}
}
getRichStringCellValue方法源码
public String getStringCellValue() {
HSSFRichTextString str = this.getRichStringCellValue();
return str.getString();
}
public HSSFRichTextString getRichStringCellValue() {
switch(this._cellType) {
case STRING:
return this._stringValue;
case BLANK:
return new HSSFRichTextString("");
case FORMULA:
FormulaRecordAggregate fra = (FormulaRecordAggregate)this._record;
checkFormulaCachedValueType(CellType.STRING, fra.getFormulaRecord());
String strVal = fra.getStringValue();
return new HSSFRichTextString(strVal == null ? "" : strVal);
default:
throw typeMismatch(CellType.STRING, this._cellType, false);
}
}
问题二:数字类型列的单元格不能为空
规定某一列是数字格式后,如果该列的某个单元格无数据是空白或者null,就会赋值成默认值:0;
在easypoi的"BaseExportService"这个类中的:"createDoubleCell"这个方法中它只会给数据不是null并且数据长度大于0的单元格赋值你规定的数据值,其余的会通过走”cell.setCellType(0);“这个语句将空值赋值上默认值:0.0D
流转过程:
createListCells方法中使用:
this.createDoubleCell(row, cellNum++, value == null ? "" : value.toString(), index % 2 == 0 ? this.getStyles(false, entity) : this.getStyles(true, entity), entity);
将null改变成: “”
在:createDoubleCell中给有值的赋值,并且所有数据都要走:cell.setCellType(0);
在HSSFCell这个类的方法:setCellType 中使用语句:
(第二个参数true是用于启用setValue)
this.setCellType(cellType, true, row, col, styleIndex);
从这个setCellType方法中调用:
nrec.setValue(this.getNumericCellValue());
最终将默认值0.0D赋值上:
createListCells源码:
public void createListCells(Drawing patriarch, int index, int cellNum, Object obj, List<ExcelExportEntity> excelParams, Sheet sheet, Workbook workbook, short rowHeight) throws Exception {
Row row;
if (sheet.getRow(index) == null) {
row = sheet.createRow(index);
if (rowHeight != -1) {
row.setHeight(rowHeight);
}
} else {
row = sheet.getRow(index);
if (rowHeight != -1) {
row.setHeight(rowHeight);
}
}
int k = 0;
for(int paramSize = excelParams.size(); k < paramSize; ++k) {
ExcelExportEntity entity = (ExcelExportEntity)excelParams.get(k);
Object value = this.getCellValue(entity, obj);
if (entity.getType() == BaseEntityTypeConstants.STRING_TYPE) {
this.createStringCell(row, cellNum++, value == null ? "" : value.toString(), row.getRowNum() % 2 == 0 ? this.getStyles(false, entity) : this.getStyles(true, entity), entity);
if (entity.isHyperlink()) {
row.getCell(cellNum - 1).setHyperlink(this.dataHandler.getHyperlink(row.getSheet().getWorkbook().getCreationHelper(), obj, entity.getName(), value));
}
} else if (entity.getType() == BaseEntityTypeConstants.DOUBLE_TYPE) {
this.createDoubleCell(row, cellNum++, value == null ? "" : value.toString(), index % 2 == 0 ? this.getStyles(false, entity) : this.getStyles(true, entity), entity);
if (entity.isHyperlink()) {
row.getCell(cellNum - 1).setHyperlink(this.dataHandler.getHyperlink(row.getSheet().getWorkbook().getCreationHelper(), obj, entity.getName(), value));
}
} else {
this.createImageCell(patriarch, entity, row, cellNum++, value == null ? "" : value.toString(), obj);
}
}
}
createDoubleCell源码:
public void createDoubleCell(Row row, int index, String text, CellStyle style, ExcelExportEntity entity) {
Cell cell = row.createCell(index);
if (text != null && text.length() > 0) {
cell.setCellValue(Double.parseDouble(text));
}
cell.setCellType(0);
if (style != null) {
cell.setCellStyle(style);
}
this.addStatisticsData(index, text, entity);
}