刚写完一个版本。看似能实现。读取2遍,读合并单元格信息的时候,如果能开放出来跳过row的解析 应该会好很多。简单代码贴一下。
List<CellExtra> mergeCells = readMergeCells(file) ;
excelReader = EasyExcel.read(file).useDefaultListener(false).build();
ExcelReaderSheetBuilder sheetBuilder = EasyExcel.readSheet(parseParams.sheetNo())
.headRowNumber(parseParams.headRowNumber());
if (!mergeCells.isEmpty()) {
sheetBuilder.registerReadListener(new FillMergeListener(mergeCells));
}
sheetBuilder.registerReadListener(new ModelBuildEventListener());
sheetBuilder.registerReadListener(this.dataListener);
if (Objects.nonNull(parseParams.head())) {
sheetBuilder.head(parseParams.head());
}
readSheet = sheetBuilder.build();
excelReader.read(readSheet);
private List<CellExtra> readMergeCells(File file) {
ReadMergeCellsListener readMergeCellsListener = new ReadMergeCellsListener();
EasyExcel.read(file, readMergeCellsListener).extraRead(CellExtraTypeEnum.MERGE).sheet(parseParams.sheetNo()).doRead();
return readMergeCellsListener.mergeCells;
}
private static class ReadMergeCellsListener extends AnalysisEventListener {
private List<CellExtra> mergeCells = new ArrayList<>();
@Override
public void invoke(Object data, AnalysisContext context) {
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
}
/**
* 读取额外信息:合并单元格
*/
@Override
public void extra(CellExtra extra, AnalysisContext context) {
switch (extra.getType()) {
case MERGE: {
log.debug(
"额外信息是合并单元格,而且覆盖了一个区间,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{}",
extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(),
extra.getLastColumnIndex());
mergeCells.add(extra);
break;
}
default:
}
}
}
private static class FillMergeListener extends AnalysisEventListener<Map<Integer, ReadCellData<?>>> {
private final List<CellExtra> mergedRegions;
private final Map<String, CellExtra> mergedRegionMap = new HashMap<>();
private final Set<Integer> mergedRowSet = new HashSet<>();
//上一行数据
private Map<Integer, ReadCellData<?>> last;
public FillMergeListener(List<CellExtra> mergedRegions) {
this.mergedRegions = mergedRegions;
mergedRegions.forEach(cellAddresses -> {
int firstColumn = cellAddresses.getFirstColumnIndex();
int lastColumn = cellAddresses.getLastColumnIndex();
int firstRow = cellAddresses.getFirstRowIndex();
int lastRow = cellAddresses.getLastRowIndex();
for (int i = firstRow; i <= lastRow; i++) {
mergedRowSet.add(i);
for (int j = firstColumn; j <= lastColumn; j++) {
mergedRegionMap.put(getMergedCellKey(i, j), cellAddresses);
}
}
});
}
private String getMergedCellKey(int rowIdx, int column) {
return rowIdx + "|" + column;
}
@Override
public void invoke(Map<Integer, ReadCellData<?>> data, AnalysisContext context) {
// 获取行号
ReadRowHolder readRowHolder = context.readRowHolder();
Integer rowIdx = readRowHolder.getRowIndex();
if (mergedRowSet.contains(rowIdx)) {
//尝试处理合并单元格子的数据
if (data != null) {
for (Map.Entry<Integer, ReadCellData<?>> entry : data.entrySet()) {
String cellKey = getMergedCellKey(rowIdx, entry.getKey());
if (mergedRegionMap.containsKey(cellKey)) {
mergeRegionValue(data, mergedRegionMap.get(cellKey), rowIdx, entry.getKey());
}
}
}
}
last = data;
}
private void mergeRegionValue(Map<Integer, ReadCellData<?>> dataRow,
CellExtra cellAddresses,
int rowIdx, int colIdx) {
ReadCellData<?> value = dataRow.get(colIdx);
int firstColumn = cellAddresses.getFirstColumnIndex();
int lastColumn = cellAddresses.getLastColumnIndex();
int firstRow = cellAddresses.getFirstRowIndex();
int lastRow = cellAddresses.getLastRowIndex();
if (firstRow == rowIdx) {
if (firstColumn == colIdx) {
//合并单元格的第一个格子内容,不需要处理
return;
} else {
//非合并单元格的第一个格子内容,左右合并,因为按顺序的,所以像左取值
value = dataRow.get(colIdx - 1);
dataRow.put(colIdx, value);
}
} else {
//非同一行,上下合并,向上取值
if (this.last != null) {
value = this.last.get(colIdx);
dataRow.put(colIdx, value);
}
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
}
}