解决 easypoi 循环指令合并单元格的问题
前言
使用 easypoi 循环指令时,发现下面3种情况循环会出现问题,导致excel格式错乱。
- 循环开始标识与结束标识之间存在合并单元格。
- 循环开始标识左侧存在合并单元格。
- 存在多个循环指令时。
如何解决
反编译下面这个类,在其基础上修改
cn.afterturn.easypoi.excel.export.template.ExcelExportOfTemplateUtil
循环开始标识与结束标识之间存在合并单元格,解决方法
修改 addListDataToExcel 方法
private void addListDataToExcel(Cell cell, Map<String, Object> map,String name) throws Exception {
......
// 定义循环开始行号
int startRowNum = cell.getRow().getRowNum();
......
// 定义循环结束行号
int endRowNum = 0;
while (its.hasNext()) {
Object t = its.next();
row = createRow(rowIndex, cell.getSheet(), isCreate, rowspan);
setForEeachRowCellValue(isCreate, row, cell.getColumnIndex(), t, columns, map, rowspan,
colspan, mergedRegionHelper,startRowNum);
rowIndex += rowspan;
// 每次创建行后,重新给循环结束行号赋值
endRowNum = row.getRowNum();
}
// 如果新创建行了
// 合并循环左侧竖向单元格
if (endRowNum != 0){
Sheet sheet = cell.getRow().getSheet();
int sheetMergeCount = sheet.getNumMergedRegions();
int columnIndex = cell.getColumnIndex();
for(int i = 0; i < sheetMergeCount; ++i) {
CellRangeAddress ca = sheet.getMergedRegion(i);
//int firstColumn = ca.getFirstColumn();
int lastColumn = ca.getLastColumn();
int firstRow = ca.getFirstRow();
int lastRow = ca.getLastRow();
for (int ii = 0;ii < columnIndex;ii++){
if (firstRow <= startRowNum && lastRow > startRowNum && lastColumn == ii){
ca.setLastRow(lastRow + (endRowNum - startRowNum));
}
}
}
}
}
循环开始标识左侧存在合并单元格,解决方法
修改 addListDataToExcel 方法,将循环开始行号,传入 setForEeachRowCellValue 方法
private void addListDataToExcel(Cell cell, Map<String, Object> map,String name) throws Exception {
......
// 定义循环开始行号
int startRowNum = cell.getRow().getRowNum();
......
// 处理当前行
if (its.hasNext()) {
Object t = its.next();
setForEeachRowCellValue(isCreate, cell.getRow(), cell.getColumnIndex(), t, columns, map,
rowspan, colspan, mergedRegionHelper,startRowNum);
rowIndex += rowspan - 1;
}
......
// 创建行
while (its.hasNext()) {
Object t = its.next();
row = createRow(rowIndex, cell.getSheet(), isCreate, rowspan);
setForEeachRowCellValue(isCreate, row, cell.getColumnIndex(), t, columns, map, rowspan,
colspan, mergedRegionHelper,startRowNum);
rowIndex += rowspan;
endRowNum = row.getRowNum();
}
......
}
修改 setForEeachRowCellValue 方法
// 添加参数:循环开始行号
private void setForEeachRowCellValue(boolean isCreate, Row row, int columnIndex, Object t,
List<ExcelForEachParams> columns, Map<String, Object> map,
int rowspan, int colspan,
MergedRegionHelper mergedRegionHelper,int startRowNum) throws Exception {
......
//合并对应单元格
if ((params.getRowspan() != 1 || params.getColspan() != 1)
// 存在合并单元格时,这个判断出问题了,需要注释
//&& !mergedRegionHelper.isMergedRegion(row.getRowNum() + 1, ci)
// 将第二个参数改为:循环开始行号
// 原因:这个方法原先是判断当前行这一列,是否需要合并单元格
// 如果是新创建的行,这个方法恒定返回 false ,判断出现问题
// 所以需要改为:判断循环开始行这一列,是否需要合并单元格
&& PoiCellUtil.isMergedRegion(row.getSheet(), startRowNum, ci)
) {
PoiMergeCellUtil.addMergedRegion(row.getSheet(), row.getRowNum(),
row.getRowNum() + params.getRowspan() - 1, ci,
ci + params.getColspan() - 1);
}
......
}
存在多个循环指令时,解决方法
修改 addListDataToExcel 方法
private void addListDataToExcel(Cell cell, Map<String, Object> map,String name) throws Exception {
// 每次利用foreach循环输出数据时,重新处理 mergedRegionHelper
// 原因:如果存在多个循环,前面循环时,下面的模板指令所在单元格的行号会发生变化,此时 mergedRegionHelper 中的缓存没有发生相应变化,需要重新获取一下 mergedRegionHelper
mergedRegionHelper = new MergedRegionHelper(cell.getSheet());
......
}
注意
- 反编译 cn.afterturn.easypoi.excel.export.template.ExcelExportOfTemplateUtil 这个类后,爆红的代码,需要修改。
- setForEeachRowCellValue 方法添加参数:循环开始行号后,所有引用这个方法的地方,都需要修改。
正文到此结束