poi的XSSFWorkbook转SXSSFWorkbook发现的问题

1. 背景

        项目上需要对报表进行打印,前提是用户自己上传excel模板,设置页眉页脚及表格样式,由后端根据参数获取模板后和数据后,将数据写入excel中返回给前端转为pdf预览及打印。已有接口是用poi的SXSSFWorkbook操作excel,具体实现这篇文章已经说明。

        现在需求变更,需要根据用户在模板中设置的表达式,将数据继承模板中样式输出到excel表格中。这样能让用户自定义设置表格样式,而非系统给定默认样式。

2. 遇到的问题

        实现过程中,需要获取模板中已设置的excel,并循环所有行找到表达式填充数据。通过SXSSFWorkbook无法直接将流转换,只能先转换为XSSFWorkbook,再实例化SXSSFWorkbook。具体请看上面提到的文章内容

XSSFWorkbook workbook = new XSSFWorkbook(file1);
// 转换为SXSSFWorkbook
SXSSFWorkbook wbook = new SXSSFWorkbook(workbook);

使用wbook.getSheetAt(0).getLastRowNum()却无法获取模板中设置的最后行号。查看源码

    public SXSSFWorkbook(XSSFWorkbook workbook){
    	this(workbook, DEFAULT_WINDOW_SIZE);
    }

而使用workbook.getSheetAt(0).getLastRowNum()却能获取到。

而且有点难受的是,使用wbook.getSheetAt(0).getRow(0)获取到的为null,而使用wbook.getSheetAt(0).createRow(0)想去创建新行覆盖的时候又抛出异常,原因看以下源码

    /**
     * Create a new row within the sheet and return the high level representation
     *
     * @param rownum  row number
     * @return high level Row object representing a row in the sheet
     * @throws IllegalArgumentException If the max. number of rows is exceeded or 
     *      a rownum is provided where the row is already flushed to disk.
     * @see #removeRow(Row)
     */
    @Override
    public SXSSFRow createRow(int rownum)
    {
        int maxrow = SpreadsheetVersion.EXCEL2007.getLastRowIndex();
        if (rownum < 0 || rownum > maxrow) {
            throw new IllegalArgumentException("Invalid row number (" + rownum
                    + ") outside allowable range (0.." + maxrow + ")");
        }

        // attempt to overwrite a row that is already flushed to disk
        if(rownum <= _writer.getLastFlushedRow() ) {
            throw new IllegalArgumentException(
                    "Attempting to write a row["+rownum+"] " +
                    "in the range [0," + _writer.getLastFlushedRow() + "] that is already written to disk.");
        }

        // attempt to overwrite a existing row in the input template
        if(_sh.getPhysicalNumberOfRows() > 0 && rownum <= _sh.getLastRowNum() ) {
            throw new IllegalArgumentException(
                    "Attempting to write a row["+rownum+"] " +
                            "in the range [0," + _sh.getLastRowNum() + "] that is already written to disk.");
        }

        SXSSFRow newRow = new SXSSFRow(this);
        _rows.put(rownum, newRow);
        allFlushed = false;
        if(_randomAccessWindowSize >= 0 && _rows.size() > _randomAccessWindowSize) {
            try {
               flushRows(_randomAccessWindowSize);
            } catch (IOException ioe) {
                throw new RuntimeException(ioe);
            }
        }
        return newRow;
    }

代码走到第三个if的时候被逮住住抛出异常,真正有数据的是_sh,而不是_rows。但代码又不能获取到_sh

吐槽一下:无法理解写这个工具类的开发是怎么思考问题的,既让我们用,用起来又很难受

3. 解决方案

如果没有版本要求,时间也不够充裕,还是降低版本,使用XSSFWorkbook操作excel吧,懒得去纠结了,更有可能需要降低到HSSFWorkbook。反正操作方式基本相同,只是兼容的excel有些出入而已。

如果一定需要使用SXSSFWorkbook,那就去研究研究代码,看看如何解决这些问题。本人迫于时间紧任务重,只能委曲求全降低版本先实现功能了。

你可能感兴趣的:(java,poi)