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);
+ }
+ }
+ }
}