简体   繁体   中英

Issue with export CrossTab data into excel sheet using Java Apache POI 3.15 version

I am collecting data from my company portal and trying to export it into an excel sheet. I successfully completed for non-crosstab report data. But the issue is coming when the data has crosstab.

Data: 在此处输入图片说明

I have saved in data in ArrayList best on my best understanding.

1.

rowHeader:[Quarter, Subcategory]

2.

rowElement:[2016 Q1, 2016 Q2, 2016 Q3, 2016 Q4, Audio Equipment, Cameras, Computers, Electronics - Miscellaneous, TV's, Video Equipment]

3.

columnHeader:[Year, 2016]

4.

columnHeaders[Quarter, Subcategory, Year, 2016]

5.

metricsColumn:[Metrics, Profit, Profit Forecast, Profit Margin, Revenue, Revenue Forecast]

6.

listData:[[$9,579, $8,823, 19.42%, $49,320, $ 39,456], [$11,449, $9,619, 20.07%, $57,040, $ 53,047], [$4,901, $3,784, 20.02%, $24,480, $ 21,298], [$12,444, $9,525, 19.89%, $62,576, $ 53,815], [$8,820, $8,059, 20.19%, $43,675, $ 35,814], [$16,375, $12,986, 20.44%, $80,130, $ 70,514], [$8,526, $6,929, 15.78%, $54,020, $ 49,698], [$11,602, $9,578, 17.31%, $67,032, $ 63,680], [$4,675, $4,380, 16.83%, $27,780, $ 25,752], [$11,699, $9,421, 16.60%, $70,469, $ 54,966], [$9,386, $7,179, 17.52%, $53,563, $ 49,974], [$10,150, $9,213, 16.96%, $59,864, $ 48,490], [$8,508, $6,772, 17.16%, $49,571, $ 47,092], [$16,429, $13,529, 18.52%, $88,712, $ 83,389], [$6,009, $5,391, 18.05%, $33,295, $ 29,200], [$11,792, $9,791, 17.21%, $68,534, $ 64,285], [$9,243, $7,952, 17.15%, $53,886, $ 49,953], [$14,282, $11,679, 18.03%, $79,193, $ 74,441], [$10,999, $8,538, 15.60%, $70,511, $ 65,575], [$14,475, $11,433, 16.32%, $88,718, $ 78,515], [$5,765, $5,029, 16.77%, $34,373, $ 31,847], [$11,335, $9,567, 15.28%, $74,168, $ 62,672], [$11,990, $11,230, 16.83%, $71,255, $ 64,414], [$13,864, $11,328, 16.87%, $82,203, $ 70,695]]

Till so far, I successfully, completed exporting Headers section.

在此处输入图片说明

I am struggling, now exporting data into an excel sheet because of the crosstab we need to do column merge and row merge for every Quarters and Years.

If someone can help me, to write any sample code/ pseudo code for it, it would be a very very helpful for me. I ave stuck with this issue from the last 4 days. I am not getting how to do this part as I never used any exclsheet API. here I am using APACHE POI -3.15 version.

Code till so far, which export Header section:

//Create a Row
        Row headerRow = sheet.createRow(0);

        //int totalcolumns = rowHeader.size() + columnHeader.size();

        int mergeHeader = 0;
        if(metricsColumn != null) {
            mergeHeader = 1;
        }
        //Create Cells //[Quarter, Subcategory, Year, 2016]
        int  j = rowHeader.size();
        int row = 0;
        for (int i = 0; i < columnHeaders.size(); i++) {

            Cell cell = headerRow.createCell(i);
            cell.setCellValue(columnHeaders.get(i));
            if(j > 0) {
                sheet.addMergedRegion(new CellRangeAddress(row, mergeHeader, i, i));


            }
            j--;
            if (i == columnHeaders.size() - 1 && metricsColumn.size() > 0) {
                sheet.addMergedRegion(new CellRangeAddress(0,0,i,i + metricsColumn.size() - 2));
            }
            cell.setCellStyle(headerCellStyle);
        }


        int  k = 0;
        int rowNum1 = 1;
        int cellNum1 = 2;
        Row row1 = sheet.createRow(rowNum1);
        for (int i = rowHeader.size(); i < metricsColumn.size(); i++) {
            while (k < metricsColumn.size()) {
                Cell cell = row1.createCell(cellNum1++);
                cell.setCellValue(metricsColumn.get(k));
                cell.setCellStyle(headerCellStyle);
                k++;
            }
        }

I would make the structures for headers and data a little bit different:

The headers for example:

  String[][] headers = new String[][] {
   new String[] {"Quarter", "Subcategory", "Year",    "2016",    null,              null,            null,      null},
   new String[] { null,      null,         "Metrics", "Profit", "Profit Forecast", "Profit Margin", "Revenue", "Revenue Forecast"}
  };

Maybe List<List<String>> also would be possible.

The row headers:

  String[] quarters = new String[]{"2016 Q1", "2016 Q2", "2016 Q3", "2016 Q4"};
  String[] subcategories = new String[]{"Audio Equipment", "Cameras", "Computers", "Electronics - Miscellaneous", "TV's", "Video Equipment"};

Maybe List<String> also would be possible.

The values:

  Double[][] values = new Double[][]{
   new Double[]{9579d, 8823d, .1942, 49320d,39456d}, 
   new Double[]{11449d, 9619d, .2007, 57040d, 53047d}, 
   ...
   new Double[]{13864d, 11328d, .1687, 82203d, 70695d}
  };

Maybe List<List<Double>> also would be possible.

Then I would also provide basic formatting instructions in structures. So it is later possible to set them using loops.

For example the basic table structure:

  int[] columnWidths = new int[]{15*256, 15*256, 15*256, 13*256, 13*256, 13*256, 13*256, 13*256};

For example the headers horizontal alignment:

  HorizontalAlignment[][] horizontalAlignments = new HorizontalAlignment[][]{
   new HorizontalAlignment[]{HorizontalAlignment.LEFT, HorizontalAlignment.CENTER, HorizontalAlignment.LEFT, HorizontalAlignment.CENTER, null, null, null, null},
   new HorizontalAlignment[]{null, null, HorizontalAlignment.RIGHT, HorizontalAlignment.CENTER, HorizontalAlignment.CENTER, HorizontalAlignment.CENTER, HorizontalAlignment.CENTER, HorizontalAlignment.CENTER}
  };

And the merged regions for the headers:

  int[][] headerMergedRegions = new int[][]{
   new int[]{0, 0, 3, 7},
   new int[]{0, 1, 0, 0},
   new int[]{0, 1, 1, 1}
  };

Then I would set the much used number formats in default column styles:

  String[] columnCellStyles = new String[]{"default", "default", "default", "currency", "currency", "percent", "currency", "currency"};
...
   // creating default cell style having default font
   CellStyle defaultCellStyle = workbook.createCellStyle();
   defaultCellStyle.setFont(defaultFont);

   // we need currency style for numbers later
   CellStyle currency = workbook.createCellStyle();
   currency.cloneStyleFrom(defaultCellStyle);
   currency.setDataFormat(format.getFormat("$#,##0"));

   // we need percent style for numbers later
   CellStyle percent = workbook.createCellStyle();
   percent.cloneStyleFrom(defaultCellStyle);
   percent.setDataFormat(format.getFormat("0.00%"));
...
   // set default column styles
   for (int c = 0; c < columnCellStyles.length; c++) {
    String style = columnCellStyles[c];
    if ("default".equals(style)) {
     sheet.setDefaultColumnStyle(c, defaultCellStyle);
    } else if ("currency".equals(style)) {
     sheet.setDefaultColumnStyle(c, currency);
    } else if ("percent".equals(style)) {
     sheet.setDefaultColumnStyle(c, percent);
    }
   }

So when we set the values later, the cell styles can come from default column style. For this a method CellStyle getPreferredCellStyle(Cell cell) could be used.

For formatting I would rely on methods from CellUtil . So not all needed CellStyles needs to be created on workbook level but can be set to the cell into the loops.

For cell borders I would use PropertyTemplate . This makes setting borders much more easier.

Complete example:

import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCell;

import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellUtil;
import org.apache.poi.ss.util.PropertyTemplate;

import java.util.Map;
import java.util.HashMap;

class CreateExcelSpecial {

 static CellStyle getPreferredCellStyle(Cell cell) {
  // a method to get the preferred cell style for a cell
  // this is either the already applied cell style
  // or if that not present, then the row style (default cell style for this row)
  // or if that not present, then the column style (default cell style for this column)
  CellStyle cellStyle = cell.getCellStyle();
  // if no explicit cell style applied then cellStyle.getIndex() is 0 for XSSF
  // or 15 (0xF = the index to the default ExtendedFormatRecord (0xF)) for HSSF
  if ((cell instanceof XSSFCell && cellStyle.getIndex() == 0) || (cell instanceof HSSFCell && cellStyle.getIndex() == 15)) cellStyle = cell.getRow().getRowStyle();
  if (cellStyle == null) cellStyle = cell.getSheet().getColumnStyle(cell.getColumnIndex());
  if (cellStyle == null) cellStyle = cell.getCellStyle();
  return cellStyle;
 }

 public static void main(String[] args) throws Exception {

  // the data

  // basic table structure
  int[] columnWidths = new int[]{15*256, 15*256, 15*256, 13*256, 13*256, 13*256, 13*256, 13*256};
  String[] columnCellStyles = new String[]{"default", "default", "default", "currency", "currency", "percent", "currency", "currency"};

  // headers content and formatting
  String[][] headers = new String[][] {
   new String[] {"Quarter", "Subcategory", "Year",    "2016",    null,              null,            null,      null},
   new String[] { null,      null,         "Metrics", "Profit", "Profit Forecast", "Profit Margin", "Revenue", "Revenue Forecast"}
  };
  HorizontalAlignment[][] horizontalAlignments = new HorizontalAlignment[][]{
   new HorizontalAlignment[]{HorizontalAlignment.LEFT, HorizontalAlignment.CENTER, HorizontalAlignment.LEFT, HorizontalAlignment.CENTER, null, null, null, null},
   new HorizontalAlignment[]{null, null, HorizontalAlignment.RIGHT, HorizontalAlignment.CENTER, HorizontalAlignment.CENTER, HorizontalAlignment.CENTER, HorizontalAlignment.CENTER, HorizontalAlignment.CENTER}
  };
  VerticalAlignment[][] verticalAlignments = new VerticalAlignment[][]{
   new VerticalAlignment[]{VerticalAlignment.TOP, VerticalAlignment.TOP, VerticalAlignment.CENTER, VerticalAlignment.CENTER, null, null, null, null},
   new VerticalAlignment[]{null, null, VerticalAlignment.BOTTOM, VerticalAlignment.BOTTOM, VerticalAlignment.BOTTOM, VerticalAlignment.BOTTOM, VerticalAlignment.BOTTOM, VerticalAlignment.BOTTOM}
  };
  Boolean[][] wrapTexts = new Boolean[][]{
   new Boolean[]{false, false, false, false, null, null, null, null},
   new Boolean[]{null, null, false, false, true, true, false, true}
  };
  int[][] headerMergedRegions = new int[][]{
   new int[]{0, 0, 3, 7},
   new int[]{0, 1, 0, 0},
   new int[]{0, 1, 1, 1}
  };

  // row headers
  String[] quarters = new String[]{"2016 Q1", "2016 Q2", "2016 Q3", "2016 Q4"};
  String[] subcategories = new String[]{"Audio Equipment", "Cameras", "Computers", "Electronics - Miscellaneous", "TV's", "Video Equipment"};

  // data
  Double[][] values = new Double[][]{
   new Double[]{9579d, 8823d, .1942, 49320d,39456d}, 
   new Double[]{11449d, 9619d, .2007, 57040d, 53047d}, 
   new Double[]{4901d, 3784d, .2002, 24480d, 21298d}, 
   new Double[]{12444d, 9525d, .1989, 62576d, 53815d}, 
   new Double[]{8820d, 8059d, .2019, 43675d, 35814d}, 
   new Double[]{16375d, 12986d, .2044, 80130d, 70514d}, 
   new Double[]{8526d, 6929d, .1578, 54020d, 49698d},  
   new Double[]{11602d, 9578d, .1731, 67032d, 63680d},  
   new Double[]{4675d, 4380d, .1683, 27780d, 25752d}, 
   new Double[]{11699d, 9421d, .1660, 70469d, 54966d}, 
   new Double[]{9386d, 7179d, .1752, 53563d, 49974d}, 
   new Double[]{10150d, 9213d, .1696, 59864d, 48490d},  
   new Double[]{8508d, 6772d, .1716, 49571d, 47092d}, 
   new Double[]{16429d, 13529d, .1852, 88712d, 83389d}, 
   new Double[]{6009d, 5391d, .1805, 33295d, 29200d},  
   new Double[]{11792d, 9791d, .1721, 68534d, 64285d}, 
   new Double[]{9243d, 7952d, .1715, 53886d, 49953d}, 
   new Double[]{14282d, 11679d, .1803, 79193d, 74441d}, 
   new Double[]{10999d, 8538d, .1560, 70511d, 65575d}, 
   new Double[]{14475d, 11433d, .1632, 88718d, 78515d}, 
   new Double[]{5765d, 5029d, .1677, 34373d, 31847d}, 
   new Double[]{11335d, 9567d, .1528, 74168d, 62672d}, 
   new Double[]{11990d, 11230d, .1683, 71255d, 64414d}, 
   new Double[]{13864d, 11328d, .1687, 82203d, 70695d}
  };

  try (Workbook workbook = new XSSFWorkbook(); 
       FileOutputStream fileout = new FileOutputStream("./Excel.xlsx") ) {

   // we need PropertyTemplate later
   PropertyTemplate propertyTemplate = new PropertyTemplate();

   // we need properties map for cell styles later
   Map<String, Object> properties;

   // we need DataFormat later
   DataFormat format = workbook.createDataFormat();

   // creating default font
   Font defaultFont = workbook.createFont();
   defaultFont.setFontName("Calibri");
   defaultFont.setFontHeightInPoints((short)12);

   // we need font in bold and white for headings
   Font defaultFontWhite = workbook.createFont();
   defaultFontWhite.setFontName("Calibri");
   defaultFontWhite.setFontHeightInPoints((short)12);
   defaultFontWhite.setBold(true);
   defaultFontWhite.setColor(IndexedColors.WHITE.getIndex());

   // creating default cell style having default font
   CellStyle defaultCellStyle = workbook.createCellStyle();
   defaultCellStyle.setFont(defaultFont);

   // we need currency style for numbers later
   CellStyle currency = workbook.createCellStyle();
   currency.cloneStyleFrom(defaultCellStyle);
   currency.setDataFormat(format.getFormat("$#,##0"));

   // we need percent style for numbers later
   CellStyle percent = workbook.createCellStyle();
   percent.cloneStyleFrom(defaultCellStyle);
   percent.setDataFormat(format.getFormat("0.00%"));


   Sheet sheet = workbook.createSheet(); 

   // set column widths
   for (int c = 0; c < columnWidths.length; c++) sheet.setColumnWidth(c, columnWidths[c]); 

   // set default column styles
   for (int c = 0; c < columnCellStyles.length; c++) {
    String style = columnCellStyles[c];
    if ("default".equals(style)) {
     sheet.setDefaultColumnStyle(c, defaultCellStyle);
    } else if ("currency".equals(style)) {
     sheet.setDefaultColumnStyle(c, currency);
    } else if ("percent".equals(style)) {
     sheet.setDefaultColumnStyle(c, percent);
    }
   }

   int rowIdx = 0; // looping row index
   int colIdx = 0; // looping column index

   // input and format headers
   int i = 0;
   for (String[] headerRow : headers) {
    Row row = sheet.createRow(rowIdx++);
    colIdx = 0;
    int j = 0;
    for (String header : headerRow) {
     Cell cell = row.createCell(colIdx++);
     cell.setCellValue(header);
     properties = new HashMap<String, Object>();
     properties.put(CellUtil.FILL_PATTERN, FillPatternType.SOLID_FOREGROUND);
     properties.put(CellUtil.FILL_FOREGROUND_COLOR, IndexedColors.BLUE.getIndex()); //do using only IndexedColors for fills
     properties.put(CellUtil.FONT, defaultFontWhite.getIndexAsInt()); // white font
     if (horizontalAlignments.length == headers.length) {
      HorizontalAlignment[] hAligns = horizontalAlignments[i];
      if (hAligns.length == headerRow.length) {
       HorizontalAlignment hAlign = hAligns[j];
       properties.put(CellUtil.ALIGNMENT, hAlign); // horizontal alignment
      }
     }
     if (verticalAlignments.length == headers.length) {
      VerticalAlignment[] hAligns = verticalAlignments[i];
      if (hAligns.length == headerRow.length) {
       VerticalAlignment vAlign = hAligns[j];
       properties.put(CellUtil.VERTICAL_ALIGNMENT, vAlign); // vertical alignment
      }
     }
     if (wrapTexts.length == headers.length) {
      Boolean[] isWrapTexts = wrapTexts[i];
      if (isWrapTexts.length == headerRow.length) {
       Boolean isWrapText = isWrapTexts[j];
       properties.put(CellUtil.WRAP_TEXT, isWrapText); // wrap text
      }
     }
     CellUtil.setCellStyleProperties(cell, properties); //do using CellUtil for **add** new properties to already applied cell styles
     j++;
    }
    i++;
   }
   // set header merged regions
   for (int[] mergedRegion : headerMergedRegions) {
    if (mergedRegion.length == 4) {
     sheet.addMergedRegion(new CellRangeAddress(mergedRegion[0], mergedRegion[1], mergedRegion[2], mergedRegion[3]));
    }
   }
   // draw header borders
   propertyTemplate.drawBorders(new CellRangeAddress(0, headers.length-1, 0, headers[0].length-1), BorderStyle.MEDIUM, IndexedColors.WHITE.getIndex(), BorderExtent.ALL); //since we have merged regions we can simply drawing all borders here

   // input and format row headers
   for (String quarter : quarters) {
    Row row = sheet.createRow(rowIdx++);
    Cell cell = row.createCell(0); // quarter in column 0 (A)
    cell.setCellValue(quarter);
    CellUtil.setVerticalAlignment(cell, VerticalAlignment.TOP); // quarter cells are top aligned
    for (String subcategory : subcategories) {
     cell = row.createCell(1); // subcategory in column 1 (B)
     cell.setCellValue(subcategory);
     sheet.addMergedRegion(new CellRangeAddress(rowIdx, rowIdx, 1, 2));
     row = sheet.createRow(rowIdx++);
    }
    rowIdx--;
    sheet.addMergedRegion(new CellRangeAddress(rowIdx-subcategories.length, rowIdx-1, 0, 0));
   }

   rowIdx -= quarters.length * subcategories.length; // reset the rowIdx

   // input values - number formats came from default column style
   for (Double[] rowValues : values) {
    Row row = sheet.getRow(rowIdx++); //get the row instead of creating it
    colIdx = 3; // values are from column 3 (D) on
    for (Double value : rowValues) {
     Cell cell = row.createCell(colIdx++);
     cell.setCellValue(value);
     cell.setCellStyle(getPreferredCellStyle(cell));
    }
   }

   // draw data borders
   propertyTemplate.drawBorders(new CellRangeAddress(headers.length, headers.length+values.length-1, 0, headers[0].length-1), BorderStyle.MEDIUM, IndexedColors.LIGHT_ORANGE.getIndex(), BorderExtent.ALL); //since we have merged regions we can simply drawing all borders here

   //apply the PropertyTemplate borders
   propertyTemplate.applyBorders(sheet);

   workbook.write(fileout);
  }

 }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM