java - Excel在循环过程中的列分布行为,可能吗?

标签 java apache-poi export-to-excel

使用 Apache POI 3.9,我想将一些值映射到与此类似的 Excel 模板:

Excel template with data

看起来很简单,至少对于 Seller 表来说是这样,我可以在其中毫无问题地映射我的 bean 中的值。

但是,我面临的问题与 Products 表有关,因为我需要为每一列设置 bean 中的数据,这使得逻辑有点困难很复杂,因为在循环过程中我需要查找下一列字母:

例如我的第一个产品数据将设置在B7下,然后设置在C7、D7、E7等直到循环结束。

(请注意,对于此示例模板,我仅显示产品的“名称”属性,但每个产品在现实生活中都有大约 35 个属性,这就是为什么我没有按行显示数据,因为表格在水平 View 中对用户来说看起来不太友好)。

所以,我的问题是:

What happen If my products count is more than the total letters of the alphabet, how can I get the right column and cell during the loop process to set my product bean data following Excel column distribution?

“Excel 列分布” 我的意思是:

例如在 Excel 中,当转到包含字母表最后一个字母 “Z” 的列时,列将继续显示 < em>AA、AB、AC 等。

Example of Excel columns distribution

可能吗?

这是我尝试过的(使用虚拟数据),这将一直有效,直到进入字母“Z”列:

此代码段中使用的空 Excel 模板可以从以下位置下载: https://www.dropbox.com/s/eo0s54o9vkqhlbl/template.xls

package com.app.test;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.IndexedColors;
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.CellReference;


/**
 * Test class for generating Excel sheet
 */
public class ExportTest
{
    public static void main(String[] args) throws IOException
    {
        CellReference ref;

        // Load template
        InputStream fis = ExportTest.class.getResourceAsStream("/template.xls");
        Workbook workbook = new HSSFWorkbook(fis);
        fis.close();

        // Constants
        final String TBL_FIRSTCOLUMN = "B"; // Starting product table column at sheet (in which the first product data will be set)
        final int MAX_PRODUCTS = 25; // Max. products added to the dummy products list (this will set the last product to the "Z" column)
        final int TBL_STARTROW = 7; // Starting product table row number at sheet (in which the first product data will be set)
        final int TBL_ATTR_ROWS = 1; // Number of attribute rows at products table (in this case just "Name")

        // Generate dummy data with seller information
        LinkedHashMap<String, String> cellMap = new LinkedHashMap<String, String>();
        cellMap.put("B2", "1");
        cellMap.put("B3", "Company");
        cellMap.put("B4", "US");

        // Generate dummy data with product information
        List<String> products = new ArrayList<String>();
        for(int i = 0; i < MAX_PRODUCTS; ++i) {
            products.add("Chocolate");
        }

        // Declare style for cells
        CellStyle style = workbook.createCellStyle();
        style.setBorderLeft(CellStyle.BORDER_THIN);
        style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
        style.setBorderRight(CellStyle.BORDER_THIN);
        style.setRightBorderColor(IndexedColors.BLACK.getIndex());
        style.setBorderTop(CellStyle.BORDER_THIN);
        style.setTopBorderColor(IndexedColors.BLACK.getIndex());
        style.setBorderBottom(CellStyle.BORDER_THIN);
        style.setBottomBorderColor(IndexedColors.BLACK.getIndex());

        // Get template sheet
        Sheet sheet = workbook.getSheetAt(0);

        // Set values to "Seller" table
        for(Map.Entry<String, String> entry : cellMap.entrySet()) {
            ref = new CellReference(entry.getKey());
            sheet.getRow(ref.getRow()).getCell(ref.getCol()).setCellValue(entry.getValue());
        }

        // Set values to "Products" table
        for(int i = 0; i < products.size(); ++i) {

            // Get product name
            String name = products.get(i);
            String num = String.valueOf(i + 1);

            // Get char representation of the letter, this will allow me to get
            // C, D, E...Z columns but then I will get a IllegalArgumentException
            // if my products count exceed the alphabet letters. At this point I'll 
            // need to follow Excel column distribution behavior.
            String nextLetter = String.valueOf((char)(TBL_FIRSTCOLUMN.charAt(0) + i));

            for(int j = 0; j < TBL_ATTR_ROWS; ++j) {
                // Get cell reference of B7 then C7, etc
                ref = new CellReference(nextLetter + (TBL_STARTROW + j));

                // Check if row/cell exists, otherwise it will throw NullPointerException when trying to get each one
                Row row = sheet.getRow(ref.getRow());
                if(row == null) {
                    row = sheet.createRow(ref.getRow());
                }
                Cell cell = row.getCell(ref.getCol());
                if(cell == null) {
                    cell = row.createCell(ref.getCol());
                }

                // Set value and style to cell
                cell.setCellValue(name + num);
                cell.setCellStyle(style);
            }
        }

        // Write workbook to file
        String path = String.format("%s%s%s", System.getProperty("user.home"), System.getProperty("file.separator"), "exported.xls");
        OutputStream out = new FileOutputStream(new File(path));
        workbook.write(out);
        out.close();
    }
}

然后,如果产品数量超过字母表字母,我将得到以下异常:

Exception in thread "main" java.lang.IllegalArgumentException: Invalid column index (-11). Allowable column range for BIFF8 is (0..255) or ('A'..'IV') at org.apache.poi.hssf.usermodel.HSSFCell.checkBounds(HSSFCell.java:939) at org.apache.poi.hssf.usermodel.HSSFCell.(HSSFCell.java:153) at org.apache.poi.hssf.usermodel.HSSFRow.createCell(HSSFRow.java:148) at org.apache.poi.hssf.usermodel.HSSFRow.createCell(HSSFRow.java:126) at org.apache.poi.hssf.usermodel.HSSFRow.createCell(HSSFRow.java:39) at com.app.test.ExportTest.main(ExportTest.java:99)

(要复制此尝试,请使用 MAX_PRODUCTS = 26不是 27 - 字母计数 - 因为我们从 Excel 工作表上的 B 列开始)。

任何帮助将不胜感激,谢谢!

最佳答案

您在 Apache POI 中调用实用程序方法 -- CellReference.convertNumToColString将列号映射到 Excel 列名称。

Takes in a 0-based base-10 column and returns a ALPHA-26 representation. eg column #3 -> D

由于您是从“B”列 (1) 开始,因此请先将 1 添加到 i

String nextLetter = String.valueOf(CellReference.convertNumToColString(i + 1));

关于java - Excel在循环过程中的列分布行为,可能吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24174156/

相关文章:

java - 直接从 Java 中的 REST API 响应流将大型 JSON 保存为文本

java - 更改 Java 数组的维数

java - Apache POI 在电子表格中仅记录 1 行

java - 删除包含特定字符串的多行

c# - 将数据网格导出到 excel asp

c# - 导入和导出 Excel - 什么是最好的库?

java - http.nonProxyHosts 的有效正则表达式

java - hibernate 4 @OneToMany 列表<字符串>

java - 将 MCQ 从字符串文件中提取到单个 Questions 对象的 Arraylist 中

javascript - 使用 JavaScript 使用 UTF-8(例如希腊语)编码将 JSON 导出到 CSV 或 Excel