This commit is contained in:
haomingming 2026-01-04 13:46:45 +08:00
parent e9970d5057
commit 7881d80b35

View File

@ -7,7 +7,9 @@ import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import java.io.IOException;
import java.util.List;
public class CustomExcelWriteHandler implements WriteHandler {
@ -15,6 +17,9 @@ public class CustomExcelWriteHandler implements WriteHandler {
private final double totalTax;
private final double totalTotal;
private final int dataSize;
private boolean totalRowCreated = false;
// 缓存 Workbook afterSheetCreate 中初始化
private Workbook workbook;
public CustomExcelWriteHandler(double totalActual, double totalTax, double totalTotal, int dataSize) {
this.totalActual = totalActual;
@ -24,8 +29,8 @@ public class CustomExcelWriteHandler implements WriteHandler {
}
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
// 工作表创建后先处理大标题表头样式列宽此时还未写入数据行未刷盘
Workbook workbook = writeWorkbookHolder.getWorkbook();
// 初始化 Workbook 缓存关键兼容低版本
this.workbook = writeWorkbookHolder.getWorkbook();
Sheet sheet = writeSheetHolder.getSheet();
// 1. 处理大标题第0行
@ -33,7 +38,6 @@ public class CustomExcelWriteHandler implements WriteHandler {
titleRow.setHeightInPoints(30);
Cell titleCell = titleRow.createCell(0);
titleCell.setCellValue("人工肝诊疗病例征集项目专家劳务费表");
// 合并大标题单元格0行0列到0行最后一列
sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 13));
// 大标题样式
CellStyle titleStyle = workbook.createCellStyle();
@ -60,84 +64,91 @@ public class CustomExcelWriteHandler implements WriteHandler {
headRow.setHeightInPoints(25);
}
public void afterWorkbookDispose(WriteWorkbookHolder writeWorkbookHolder) {
// 数据写入完成后处理合计行和数据行高此时所有数据行已写入但合计行是新创建的未刷盘
Workbook workbook = writeWorkbookHolder.getWorkbook();
Sheet sheet = workbook.getSheetAt(0);
// 关键数据行写入完成后创建合计行兼容低版本
public void afterRowDispose(WriteSheetHolder writeSheetHolder, Row row, Integer relativeRowIndex, Boolean isHead) throws IOException {
// 仅在最后一行数据写入后创建合计行且未创建过
if (!totalRowCreated && relativeRowIndex != null && relativeRowIndex == dataSize - 1) {
Sheet sheet = writeSheetHolder.getSheet();
// 1. 设置数据行行高第2行到数据最后一行
for (int i = 2; i <= dataSize + 1; i++) { // 数据从第2行开始共dataSize行
Row row = sheet.getRow(i);
if (row != null) {
row.setHeightInPoints(22);
// 修正合计行索引0=大标题1=表头2~1+dataSize=数据2+dataSize=合计
int totalRowIndex = 2 + dataSize;
Row totalRow = sheet.createRow(totalRowIndex);
totalRow.setHeightInPoints(22);
// 合计行样式黑底白字
CellStyle totalStyle = workbook.createCellStyle();
Font totalFont = workbook.createFont();
totalFont.setBold(true);
totalFont.setColor(IndexedColors.WHITE.getIndex());
totalStyle.setFont(totalFont);
totalStyle.setFillForegroundColor(IndexedColors.BLACK.getIndex());
totalStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
totalStyle.setAlignment(HorizontalAlignment.CENTER);
totalStyle.setVerticalAlignment(VerticalAlignment.CENTER);
totalStyle.setBorderTop(BorderStyle.THIN);
totalStyle.setBorderBottom(BorderStyle.THIN);
totalStyle.setBorderLeft(BorderStyle.THIN);
totalStyle.setBorderRight(BorderStyle.THIN);
// 合并前6列写合计
sheet.addMergedRegion(new CellRangeAddress(totalRowIndex, totalRowIndex, 0, 5));
Cell totalCell = totalRow.createCell(0);
totalCell.setCellValue("合计");
totalCell.setCellStyle(totalStyle);
// 实发个税应发赋值+样式
Cell actualCell = totalRow.createCell(6);
actualCell.setCellValue(totalActual);
actualCell.setCellStyle(totalStyle);
Cell taxCell = totalRow.createCell(8);
taxCell.setCellValue(totalTax);
taxCell.setCellStyle(totalStyle);
Cell totalAmtCell = totalRow.createCell(9);
totalAmtCell.setCellValue(totalTotal);
totalAmtCell.setCellStyle(totalStyle);
// 其他列补充边框
CellStyle borderStyle = workbook.createCellStyle();
borderStyle.setBorderBottom(BorderStyle.THIN);
borderStyle.setBorderTop(BorderStyle.THIN);
borderStyle.setBorderLeft(BorderStyle.THIN);
borderStyle.setBorderRight(BorderStyle.THIN);
borderStyle.setAlignment(HorizontalAlignment.CENTER);
for (int i = 0; i < 14; i++) {
if (i == 0 || i == 6 || i == 8 || i == 9) {
continue;
}
Cell cell = totalRow.getCell(i);
if (cell == null) {
cell = totalRow.createCell(i);
}
cell.setCellStyle(borderStyle);
}
// 标记合计行已创建
totalRowCreated = true;
// 强制刷新兼容SXSSF
if (sheet instanceof SXSSFSheet) {
((SXSSFSheet) sheet).flushRows();
}
}
// 2. 处理合计行
int totalRowIndex = dataSize + 2; // 合计行在数据行最后一行的下一行
Row totalRow = sheet.createRow(totalRowIndex);
totalRow.setHeightInPoints(22);
// 合计行样式黑底白字
CellStyle totalStyle = workbook.createCellStyle();
Font totalFont = workbook.createFont();
totalFont.setBold(true);
totalFont.setColor(IndexedColors.WHITE.getIndex());
totalStyle.setFont(totalFont);
totalStyle.setFillForegroundColor(IndexedColors.BLACK.getIndex());
totalStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
totalStyle.setAlignment(HorizontalAlignment.CENTER);
totalStyle.setVerticalAlignment(VerticalAlignment.CENTER);
totalStyle.setBorderTop(BorderStyle.THIN);
totalStyle.setBorderBottom(BorderStyle.THIN);
totalStyle.setBorderLeft(BorderStyle.THIN);
totalStyle.setBorderRight(BorderStyle.THIN);
// 合并前6列0-5合计
sheet.addMergedRegion(new CellRangeAddress(totalRowIndex, totalRowIndex, 0, 5));
Cell totalCell = totalRow.createCell(0);
totalCell.setCellValue("合计");
totalCell.setCellStyle(totalStyle);
// 实发6列个税8列应发9列设置值和样式
Cell actualCell = totalRow.createCell(6);
actualCell.setCellValue(totalActual);
actualCell.setCellStyle(totalStyle);
Cell taxCell = totalRow.createCell(8);
taxCell.setCellValue(totalTax);
taxCell.setCellStyle(totalStyle);
Cell totalAmtCell = totalRow.createCell(9);
totalAmtCell.setCellValue(totalTotal);
totalAmtCell.setCellStyle(totalStyle);
// 其他列补充边框样式
CellStyle borderStyle = workbook.createCellStyle();
borderStyle.setBorderBottom(BorderStyle.THIN);
borderStyle.setBorderTop(BorderStyle.THIN);
borderStyle.setBorderLeft(BorderStyle.THIN);
borderStyle.setBorderRight(BorderStyle.THIN);
borderStyle.setAlignment(HorizontalAlignment.CENTER);
for (int i = 0; i < 14; i++) {
if (i == 0 || i == 6 || i == 8 || i == 9) {
continue; // 已设置样式的列跳过
}
Cell cell = totalRow.getCell(i);
if (cell == null) {
cell = totalRow.createCell(i);
}
cell.setCellStyle(borderStyle);
// 设置数据行行高
if (row.getRowNum() >= 2 && row.getRowNum() <= 1 + dataSize) {
row.setHeightInPoints(22);
}
}
// 其他默认方法实现
// 其他默认方法无需修改
public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {}
public void beforeWorkbookCreate(WriteWorkbookHolder writeWorkbookHolder) {}
public void beforeWorkbookDispose(WriteWorkbookHolder writeWorkbookHolder) {}
public void afterWorkbookDispose(WriteWorkbookHolder writeWorkbookHolder) {}
public void afterRowCreate(WriteSheetHolder writeSheetHolder, Row row, Integer relativeRowIndex, Boolean isHead) {}
public void afterRowDispose(WriteSheetHolder writeSheetHolder, Row row, Integer relativeRowIndex, Boolean isHead) {}
public void beforeRowCreate(WriteSheetHolder writeSheetHolder, Integer rowIndex, Integer relativeRowIndex, Boolean isHead) {}
public void beforeRowDispose(WriteSheetHolder writeSheetHolder, Row row, Integer relativeRowIndex, Boolean isHead) {}
public void afterCellCreate(WriteSheetHolder writeSheetHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {}