diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/RowUtil.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/RowUtil.java index cbeb149db..f6c44c6bd 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/RowUtil.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/RowUtil.java @@ -7,9 +7,14 @@ import cn.hutool.poi.excel.cell.CellUtil; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.ss.util.CellRangeUtil; import java.util.ArrayList; import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.IntStream; /** * Excel中的行{@link Row}封装工具类 @@ -97,4 +102,86 @@ public class RowUtil { i++; } } + + /** + * 插入行 + * + * @param sheet 工作表 + * @param startRow 插入的起始行 + * @param insertNumber 插入的行数 + */ + public static void insertRow(Sheet sheet, int startRow, int insertNumber) { + if (insertNumber <= 0) { + return; + } + // 插入位置的行,如果插入的行不存在则创建新行 + Row sourceRow = Optional.ofNullable(sheet.getRow(startRow)).orElseGet(() -> sheet.createRow(insertNumber)); + // 从插入行开始到最后一行向下移动 + sheet.shiftRows(startRow, sheet.getLastRowNum(), insertNumber, true, false); + + // 填充移动后留下的空行 + IntStream.range(startRow, startRow + insertNumber).forEachOrdered(i -> { + Row row = sheet.createRow(i); + row.setHeightInPoints(sourceRow.getHeightInPoints()); + short lastCellNum = sourceRow.getLastCellNum(); + IntStream.range(0, lastCellNum).forEachOrdered(j -> { + Cell cell = row.createCell(j); + cell.setCellStyle(sourceRow.getCell(j).getCellStyle()); + }); + }); + } + + /** + * 从工作表中删除指定的行,此方法修复sheet.shiftRows删除行时会拆分合并的单元格的问题 + * + * @param row 需要删除的行 + * @see sheet.shiftRows的bug + */ + public static void removeRow(Row row) { + if (row == null) { + return; + } + int rowIndex = row.getRowNum(); + Sheet sheet = row.getSheet(); + int lastRow = sheet.getLastRowNum(); + if (rowIndex >= 0 && rowIndex < lastRow) { + List updateMergedRegions = new ArrayList<>(); + // 找出需要调整的合并单元格 + IntStream.range(0, sheet.getNumMergedRegions()) + .forEach(i -> { + CellRangeAddress mr = sheet.getMergedRegion(i); + if (!mr.containsRow(rowIndex)) { + return; + } + // 缩减以后变成单个单元格则删除合并单元格 + if (mr.getFirstRow() == mr.getLastRow() - 1 && mr.getFirstColumn() == mr.getLastColumn()) { + return; + } + updateMergedRegions.add(mr); + }); + + // 将行上移 + sheet.shiftRows(rowIndex + 1, lastRow, -1); + + // 找出删除行所在的合并单元格 + List removeMergedRegions = IntStream.range(0, sheet.getNumMergedRegions()) + .filter(i -> updateMergedRegions.stream(). + anyMatch(umr -> CellRangeUtil.contains(umr, sheet.getMergedRegion(i)))) + .boxed() + .collect(Collectors.toList()); + + sheet.removeMergedRegions(removeMergedRegions); + updateMergedRegions.forEach(mr -> { + mr.setLastRow(mr.getLastRow() - 1); + sheet.addMergedRegion(mr); + }); + sheet.validateMergedRegions(); + } + if (rowIndex == lastRow) { + Row removingRow = sheet.getRow(rowIndex); + if (removingRow != null) { + sheet.removeRow(removingRow); + } + } + } }