You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Apache POI生成带总计行的Excel表格遇警告问题排查

Apache POI生成带总计行的Excel表格时出现警告的问题

我想用Apache POI在Excel表格末尾添加总计行,写了一段生成模拟数据表格的示例代码,代码能正常运行,但打开生成的Excel工作簿时会弹出警告信息。请问这段代码存在什么问题?

示例代码

import java.awt.Desktop;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.poi.ss.SpreadsheetVersion;
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.usermodel.Workbook;
import org.apache.poi.ss.util.AreaReference;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFTable;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTable;

public class CreateTableExample {

    public static void main(String[] args) {
        try (Workbook workbook = new XSSFWorkbook()) {
            Sheet sheet = workbook.createSheet("Sheet1");

            // Create headers
            Row headerRow = sheet.createRow(0);
            for (int i = 0; i < 3; i++) {
                Cell headerCell = headerRow.createCell(i);
                headerCell.setCellValue("Header " + (i + 1));
            }

            // Create sample data
            for (int i = 1; i <= 10; i++) {
                Row dataRow = sheet.createRow(i);
                for (int j = 0; j < 3; j++) {
                    Cell dataCell = dataRow.createCell(j);
                    dataCell.setCellValue( (j + 1));
                }
            }

            Row totalRow = sheet.createRow(11);
            totalRow.createCell(0).setCellValue("Total");

            
            // Define the data range for the table
            AreaReference areaReference = new AreaReference("A1:C12", SpreadsheetVersion.EXCEL2007);

            // Create the table
            XSSFTable table = ((XSSFSheet) sheet).createTable(areaReference);
            String tableName = "MyTable";
            table.setName(tableName);
            CTTable ctTable = table.getCTTable();
            ctTable.setDisplayName(tableName);
            ctTable.setId(1);
            ctTable.setTotalsRowShown(true);
            ctTable.setTotalsRowCount(1);
            // Set the table style
            table.getCTTable().addNewTableStyleInfo();
            table.getCTTable().getTableStyleInfo().setName("TableStyleMedium9");

            
            
            String format = String.format("SUBTOTAL(109,%s[%s])",tableName,  "Header 2");
            totalRow.createCell(1).setCellFormula(String.format("SUBTOTAL(109,%s[%s])",tableName,  "Header 2"));
            totalRow.createCell(2).setCellFormula(String.format("SUBTOTAL(109,%s[%s])",tableName,  "Header 3"));
            
            
            
            // Save the workbook
            try (FileOutputStream fileOut = new FileOutputStream("workbook_with_table.xlsx")) {
                workbook.write(fileOut);
            }
            
            Desktop.getDesktop().open(new File("workbook_with_table.xlsx"));

            System.out.println("Excel file with table created successfully.");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

警告信息截图

警告截图1
警告截图2
警告截图3


问题分析与修复

核心问题

代码里同时做了两件冲突的操作:

  1. 手动创建了总计行(第12行)并给单元格设置公式
  2. 通过CTTable开启了表格自带的总计行功能(totalsRowShown(true))

Excel的表格总计行是表格结构的一部分,不需要手动创建行。手动添加的行和表格自带的总计行重复,导致Excel识别表格结构时出现错误,触发警告。另外,表格的区域范围错误包含了手动创建的行,进一步加剧了结构冲突。

修正后的代码

import java.awt.Desktop;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.poi.ss.SpreadsheetVersion;
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.usermodel.Workbook;
import org.apache.poi.ss.util.AreaReference;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFTable;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTable;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn;

public class CreateTableFixedExample {

    public static void main(String[] args) {
        try (Workbook workbook = new XSSFWorkbook()) {
            Sheet sheet = workbook.createSheet("Sheet1");

            // 创建表头
            Row headerRow = sheet.createRow(0);
            for (int i = 0; i < 3; i++) {
                Cell headerCell = headerRow.createCell(i);
                headerCell.setCellValue("Header " + (i + 1));
            }

            // 创建模拟数据(10行)
            for (int i = 1; i <= 10; i++) {
                Row dataRow = sheet.createRow(i);
                for (int j = 0; j < 3; j++) {
                    Cell dataCell = dataRow.createCell(j);
                    dataCell.setCellValue(j + 1);
                }
            }

            // 定义表格范围:仅包含表头和数据行(A1:C11)
            AreaReference areaReference = new AreaReference("A1:C11", SpreadsheetVersion.EXCEL2007);

            // 创建表格
            XSSFTable table = ((XSSFSheet) sheet).createTable(areaReference);
            String tableName = "MyTable";
            table.setName(tableName);
            CTTable ctTable = table.getCTTable();
            ctTable.setDisplayName(tableName);
            ctTable.setId(1);
            // 开启总计行功能
            ctTable.setTotalsRowShown(true);
            ctTable.setTotalsRowCount(1);

            // 设置表格样式
            ctTable.addNewTableStyleInfo();
            ctTable.getTableStyleInfo().setName("TableStyleMedium9");

            // 给每列设置总计行的内容/公式
            for (CTTableColumn col : ctTable.getTableColumns().getTableColumnList()) {
                String name = col.getName();
                switch (name) {
                    case "Header 1":
                        // 第一列显示"Total"
                        col.setTotalsRowLabel("Total");
                        break;
                    case "Header 2":
                    case "Header 3":
                        // 第二、三列使用SUBTOTAL求和(109代表忽略隐藏行的求和)
                        col.setTotalsRowFunction("sum");
                        // 或者手动设置公式:col.setTotalsRowFormula(String.format("SUBTOTAL(109,%s[%s])", tableName, name));
                        break;
                }
            }

            // 保存文件
            try (FileOutputStream fileOut = new FileOutputStream("workbook_with_table_fixed.xlsx")) {
                workbook.write(fileOut);
            }

            Desktop.getDesktop().open(new File("workbook_with_table_fixed.xlsx"));
            System.out.println("带总计行的Excel表格已成功生成。");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

关键修正点

  1. 调整表格范围:将表格区域从A1:C12改为A1:C11,只包含表头和10行数据,不包含手动创建的行
  2. 移除手动总计行:删除手动创建第12行及设置公式的代码,改用表格自带的总计行
  3. 配置列总计规则:通过CTTableColumn给每列设置总计行的内容,比如第一列显示“Total”,第二、三列设置求和功能,Excel会自动生成正确的SUBTOTAL公式
  4. 保持表格结构一致性:仅通过CTTable配置总计行,避免手动操作和表格内置功能冲突

内容的提问来源于stack exchange,提问作者pranavs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 10:26:06