JAVA APACHE-POI表

时间:2017-02-27 02:06:17

标签: java excel apache-poi

将此类放在下面,这将成为循环的一部分,这将在Excel工作表中添加许多表。

我的问题是,我无法弄清楚,如何使格式化为formatAsTable样式的表来计算总计行中的值。我把这2行代码放在一边:

cttable.setTotalsRowShown(true);
cttable.setTotalsRowCount(1);

启用过滤器,但公式不存在。我知道我有字符串值,稍后会更改,但那些不是问题。下面的完整代码,如果有人知道如何,请详细说明因为我不知道如何

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Random;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.AreaReference;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFRow;
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;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumns;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableStyleInfo;

public class formatAsTable2
{
    public static void main(String[] args)
        throws FileNotFoundException, IOException, InvalidFormatException
    {
        String[][] multi = new String[][]{
            { "Advisor", "nonContactedUTD", "appointmentsUTD", "totalWorkLoad", "notResponsiveCalls", "successfulCalls", "totalCalls", "totalIncomingEmails", "totalCommunication", "emailsSent","offerLetters","appFees","deposits" },
            { "Sharon Brown", "42", "44", "86", "62", "27", "89", "21", "220", "131" , "0", "6", "2", "0" },
            { "Elena Soteriou", "40", "44", "NULL", "62", "27", "89", "21", "230", "131" , "0", "7", "2", "0" },
            { "Helen Christou","45", "44", "86", "62", "27", "89", "21", "210", "131" , "0", "8", "2", "0" },
            { "Maria Georgiou", "48", "44", "86", "NULL", "27", "89", "21", "240", "131" , "0", "45", "2", "0" }
    };
    //(indexes start from 0) areaStart should be added to arenaRow
    int rowStart = 1;   //From which row the table to start +1
    int columnStart = 1; // From which column the table to start first column value 0

    int len = multi.length;
    int wid = multi[0].length;

    int areaRow = len + rowStart; // how many rows the table has
    int areaColumn = wid + columnStart - 1; //how many columns the table has
                                            /* Start with Creating a workbook and worksheet object */

    InputStream inp = new FileInputStream("Excel_Format_As_Table.xlsx");

    XSSFWorkbook wb = (XSSFWorkbook)WorkbookFactory.create(inp);
    XSSFSheet sheet = (XSSFSheet)wb.getSheetAt(0);

    /* Create an object of type XSSFTable */
    XSSFTable my_table = sheet.createTable();


    XSSFCellStyle my_style_1 = wb.createCellStyle();
    XSSFCellStyle my_style_0 = wb.createCellStyle();
    my_style_1.setAlignment(HorizontalAlignment.CENTER);
    my_style_1.setVerticalAlignment(VerticalAlignment.CENTER);

    XSSFFont my_font = wb.createFont();
    my_font.setBold(true);
    my_style_1.setFont(my_font);
    my_style_0.setFont(my_font);

    /* get CTTable object*/
    CTTable cttable = my_table.getCTTable();
    cttable.setTotalsRowShown(true);
    cttable.setTotalsRowCount(1);

    /* Let us define the required Style for the table */
    CTTableStyleInfo table_style = cttable.addNewTableStyleInfo();
    table_style.setName("TableStyleMedium27");

    /* Set Table Style Options */
    table_style.setShowColumnStripes(false); //showColumnStripes=0
    table_style.setShowRowStripes(true); //showRowStripes=1


                                         /* Define the data range including headers */
    AreaReference my_data_range = new AreaReference(new CellReference(rowStart, columnStart), new CellReference(areaRow, areaColumn));

    String randomCode = generateRandomChars();
    String wantedDisplayName = "MT_" + randomCode;
    String wantedName = "WN_" + randomCode;
    long id = 4L;



    java.util.List<XSSFTable> all_tables = sheet.getTables();

    for (XSSFTable a_table : all_tables) {

        if (wantedDisplayName.equals(a_table.getDisplayName())) wantedDisplayName += "_1";
        if (wantedName.equals(a_table.getName())) wantedName += "_1";
        if (a_table.getCTTable().getId() > id) id = a_table.getCTTable().getId();

        // System.out.println(wantedDisplayName);
        // System.out.println(wantedName);
        // System.out.println(id);
    }
    id++;
    cttable.setRef(my_data_range.formatAsString());
    cttable.setDisplayName(wantedDisplayName);      /* this is the display name of the table */
    cttable.setName(wantedName);    /* This maps to "displayName" attribute in <table>, OOXML */
    cttable.setId(id); //id attribute against table as long value
    cttable.addNewAutoFilter();

    CTTableColumns columns = cttable.addNewTableColumns();
    columns.setCount(areaColumn); //define number of columns

                                  /* Define Header Information for the Table */
    for (int i = columnStart; i <= areaColumn; i++)
    {
        CTTableColumn column = columns.addNewTableColumn();

        column.setName("Column" + i);
        column.setId(i + 1);
    }
    int x = -1;
    int y = -1;

    /* Add remaining Table Data */

    XSSFRow rowDate = sheet.createRow(rowStart - 1);
    XSSFCell dateCell = rowDate.createCell(0);
    dateCell.setCellValue("Date");
    dateCell.setCellStyle(my_style_0);

    for (int i = rowStart; i<areaRow; i++) //we have to populate 4 rows
    {
        ++x;
        y = -1;
        /* Create a Row */
        XSSFRow row = sheet.createRow(i);
        for (int j = columnStart; j <= areaColumn; j++) //Three columns in each row
        {
            ++y;

            XSSFCell localXSSFCell = row.createCell(j);
            if (i == rowStart)
            {
                localXSSFCell.setCellValue(multi[x][y]);
            }
            else
            {
                localXSSFCell.setCellValue(multi[x][y]);
            }

        }
        XSSFRow rowx = sheet.createRow(i + 1);
        XSSFCell cellx = rowx.createCell(1);
        cellx.setCellValue("Total");
        //cellx = rowx.createCell(2);
        //cellx.setCellFormula("SUM(C3:C6)");



        cttable.setTotalsRowShown(true);
        cttable.setTotalsRowCount(1);

    }
    XSSFRow rowDateValue = sheet.getRow(rowStart);
    XSSFCell dateCellValue = rowDateValue.createCell(0);
    dateCellValue.setCellValue("24/02/2017");
    dateCellValue.setCellStyle(my_style_1);

    sheet.addMergedRegion(new CellRangeAddress(
        rowStart, // mention first row here
        multi.length + rowStart, //mention last row here, it is 4 as we are doing a row wise merging
        0, //mention first column of merging
        0  //mention last column to include in merge
    ));

    System.out.println("X" + x);
    System.out.println("y" + y);

    my_table.updateReferences();

    inp.close();
    /* Write output as File */
    FileOutputStream fileOut = new FileOutputStream("Excel_Format_As_Table.xlsx");
    wb.write(fileOut);
    fileOut.close();

    }
        public static String generateRandomChars() {

        String candidateChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
        int length = 17;

        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            sb.append(candidateChars.charAt(random.nextInt(candidateChars
                .length())));
        }

        return sb.toString();
    }
}

1 个答案:

答案 0 :(得分:2)

主要问题是,您必须将CTTableColumnTotalsRowFunction以及单元格公式设置为总计行单元格。如果未设置,则可以通过单击总计行单元格在Excel中选择总计行功能,然后从下拉列表中选择该功能。

但在我们将单元格公式设置为总计行单元格之前,我们必须修复代码中的其他多个问题。

所有代码示例都是对您提供的代码的更改或补充:

我们应该有表格显示名称和表格名称相等。这是因为显示名称在Excel中使用,但apache poi的公式计算器使用名称。

...
    id++;
    cttable.setRef(my_data_range.formatAsString());
    cttable.setDisplayName(wantedDisplayName);      /* this is the display name of the table */
    cttable.setName(wantedDisplayName);    /* This maps to "displayName" attribute in <table>, OOXML */
    cttable.setId(id); //id attribute against table as long value
    cttable.addNewAutoFilter();
...

我们应该将列命名为“Column ...”,而不是使用正确的名称命名。这是因为apache poi公式计算器需要正确的名称来评估结构化参考公式。

...
    /* Define Header Information for the Table */
    for (int i = columnStart; i <= areaColumn; i++)
    {
        CTTableColumn column = columns.addNewTableColumn();
        column.setName(multi[0][i-1]);
        column.setId(i + 1);
        column.setTotalsRowFunction(org.openxmlformats.schemas.spreadsheetml.x2006.main.STTotalsRowFunction.SUM);
    }
...

此处TotalsRowFunction已设置为SUM

对于使用org.openxmlformats.schemas.spreadsheetml.x2006.main.STTotalsRowFunction,此示例需要FAQ-N10025中提到的所有模式ooxml-schemas-1.3.jar的完整jar。

现在我们可以将单元格公式设置为总计行单元格作为结构化参考公式。

...
        XSSFRow rowx = sheet.createRow(i + 1);
        XSSFCell cellx = rowx.createCell(1);
        cellx.setCellValue("Total");
        for (int j = columnStart+1 ; j <= areaColumn; j++) 
        {
            cellx = rowx.createCell(j);
            cellx.setCellFormula("SUBTOTAL(109," + wantedDisplayName + "[" + multi[0][j-1] + "])");
        }
...

此处SUBTOTAL(109,...设置为SUM