7

EDIT3:感谢@Leigh 的帮助,我将问题缩小到查询中的日期列。使用原始代码集和 POI,当 SpreadSheetAddRows() 尝试添加包含类似日期的单元格的非常大的查询时,页面会崩溃。我在这里做了一个错误报告:https ://bugbase.adobe.com/index.cfm?event=bug&id=3432184 。


我有一个查询要添加到一个 spreadhseet 对象,当查询的行数过多(本例中为 18583)时,该对象似乎会出错。确切的错误如下:

java.lang.ArrayIndexOutOfBoundsException: -32735
at java.util.ArrayList.get(ArrayList.java:324)
at org.apache.poi.hssf.model.WorkbookRecordList.get(WorkbookRecordList.j ava:50)
at org.apache.poi.hssf.model.Workbook.getExFormatAt(Workbook.java:787)
at org.apache.poi.hssf.usermodel.HSSFCell.getCellStyle(HSSFCell.java:901 )
at org.apache.poi.hssf.usermodel.HSSFSheet.autoSizeColumn(HSSFSheet.java :1727)
at coldfusion.excel.Excel.autoResize(Excel.java:1246)
at coldfusion.excel.Excel.autoResize(Excel.java:1240)
at coldfusion.excel.Excel.addRows(Excel.java:1214)
at coldfusion.runtime.CFPage.SpreadSheetAddRows(CFPage.java:7089) at coldfusion.runtime.CFPage.SpreadSheetAddRows(CFPage.java:7076)

以下是相关代码:

<cfset xls = spreadsheetNew()>
<cfset spreadsheetAddRow(xls, arrayToList( qryTest.getMeta().getColumnLabels() ))>
<cfset SpreadsheetFormatRow(xls, {bold=true,fgcolor="brown",color="white"}, 1)>
<cfset SpreadsheetAddRows(xls, qryTest)>
<cfheader name="Content-Disposition" value="attachment; filename=#filename#">
<cfcontent variable="#spreadsheetReadBinary(xls)#" reset="yes" type="application/vnd.ms-excel">

编辑:我之前确实成功使用了 cfspreadsheet,但它不会生成带有标题的电子表格(而且它也有需要创建一个临时文件来提供服务的缺点。)


EDIT2:根据@Leigh 的建议,我更新了 CF9/lib 文件夹中的 POI。错误现在已更改为以下内容:

<cfset SpreadsheetFormatRow(xls, {bold=true,fgcolor="brown",color="white"}, 1)>给出以下消息:org.apache.poi.hssf.util.HSSFColor.getIndexHash()Ljava/util/Hashtable;

错误代码:

java.lang.NoSuchMethodError:
org.apache.poi.hssf.util.HSSFColor.getIndexHash()Ljava/util/Hashtable;
at coldfusion.excel.Excel.getHSSFColor(Excel.java:2094)
at coldfusion.excel.Excel.findFont(Excel.java:2237)
at coldfusion.excel.Excel.getCellStyle(Excel.java:2318)
at coldfusion.excel.Excel.formatRow(Excel.java:2948)
at coldfusion.excel.Excel.formatRow(Excel.java:2963)
at coldfusion.excel.Excel.formatRow(Excel.java:2981)
at coldfusion.runtime.CFPage.SpreadSheetFormatRow(CFPage.java:7268)

评论该行,它现在再次崩溃: <cfset SpreadsheetAddRows(xls, qryTest)>

错误代码:

java.lang.IllegalStateException: The maximum number of cell styles was exceeded. You can define up to 4000 styles in a .xls workbook 
at org.apache.poi.hssf.usermodel.HSSFWorkbook.createCellStyle(HSSFWorkbook.java:1120) 
at org.apache.poi.hssf.usermodel.HSSFWorkbook.createCellStyle(HSSFWorkbook.java:73) 
at coldfusion.excel.Excel.addRow(Excel.java:1323)
at coldfusion.excel.Excel.addRows(Excel.java:1203) 
at coldfusion.runtime.CFPage.SpreadSheetAddRows(CFPage.java:7089) 
at coldfusion.runtime.CFPage.SpreadSheetAddRows(CFPage.java:7076) 
4

4 回答 4

3

我怀疑它根本与 CF 或 JRE 版本无关。至少不是直接的。这听起来像是 POI 中的一个错误。

如果您查看异常,它清楚地表明当 CF 调用尝试自动调整列大小的 POI 方法(添加查询数据之后)时会出现问题。快速搜索发现了几份类似错误的报告ArrayIndexOutOfBoundsException恰好提到了 ColdFusion):HSSFSheet.autoSizeColumn

如果您在设置超过 32767 个单元格后尝试在列上使用 org.apache.poi.hssf.usermodel.HSSFSheet 和方法 autosizecolumn(int),则会引发 ArrayOutOfBoundsException。

根据错误报告,该问题存在于版本 3.5 中,该版本与 ColdFusion 9 中包含的(主要)版本相同。其中一位 POI 开发人员建议该问题已在以后的版本中得到修复。因此,您可以尝试更新 POI jar。除此之外,如果您可以组合一个重现问题的测试用例,您可能需要提交一份错误报告

我之前确实成功地使用了 cfspreadsheet,但它不会生成带有标题的电子表格(而且它也有需要创建一个临时文件来提供服务的缺点。)

cfspreadsheet可能不会像这样做那样尝试自动调整列的大小spreadsheetAddRows,因此不会发生错误。因此,显而易见的解决方法(而不是一个很好的解决方法)是避免尝试调整列宽大小的函数。

于 2012-12-18T20:44:02.020 回答
1

如果您从代码中退后一步,只检查抛出的错误,您可以从 java 文档中得到这个这里是另一个参考

抛出以指示已使用非法索引访问数组。索引为负数或大于或等于数组的大小。

该错误还会向您显示尝试的非法索引值:-32735

现在您的问题是您没有在代码本身中指定索引值,因为您使用的是 ColdFusion 函数。该函数 ( SpreadsheetAddRows) 试图将您的查询结果转换为一个数组,然后将这些值中的每一个附加到 Excel 电子表格的行中。它正在利用底层 Java 运行时来执行这些任务,这会引发错误。所以我担心你遇到的这个限制有点卡住了。您可以尝试升级您的 ColdFusion 安装正在运行的 JRE 版本,以查看该问题是否已在较新的版本中得到解决。我相信 ColdFusion 9 附带 Java 1.6.0_14,请参见此处由于DOS 漏洞补丁,您应该至少运行 1.6.0_24. 看起来它们现在已达到 1.6.0_38 ,但您必须检查 Adob​​e 对此的支持。

如果升级 JRE 不能解决问题,那么我相信您需要更改 ColdFusion 代码以避免此问题。你说你使用CFSpreadSheet标签成功了。或者,也许您可​​以使用不同的方式将查询结果传递给SpreadsheetAddRows函数。(尽管我假设您已经用尽了这条途径。)也许循环查询并构建您自己的数组或循环查询并一次添加一行。我意识到这可能不是最佳的,但在尝试了几种不同的方法后,希望能成为一种可行的方法。

我还将在您的帖子中添加 ColdFusion 标记(不带版本号)以引起更多关注。

更新

只是想跟进 ColdFusion 9 支持的 Java 版本。我发现Charlie Arehart 的这篇博客文章讨论了 Adob​​e 对 ColdFusion 服务器 Java 升级的立场。该链接指向此处的官方 Adob​​e 帖子,其中指出将支持任何次要版本升级。所以对于 ColdFusion 9 “支持所有未来的 JDK 1.6.0_x 版本”。

于 2012-12-18T18:15:14.007 回答
1

(摘自http://poi.apache.org/spreadsheet/quick-guide.html

请注意,工作簿中唯一字体的最大数量限制为 32767(最大正短)。您应该在应用程序中重复使用字体,而不是为每个单元格创建字体。例子:

错误的:

for (int i = 0; i < 10000; i++) {
    Row row = sheet.createRow(i);
    Cell cell = row.createCell((short) 0);

    CellStyle style = workbook.createCellStyle();
    Font font = workbook.createFont();
    font.setBoldweight(Font.BOLDWEIGHT_BOLD);
    style.setFont(font);
    cell.setCellStyle(style);
}

正确的:

CellStyle style = workbook.createCellStyle();
Font font = workbook.createFont();
font.setBoldweight(Font.BOLDWEIGHT_BOLD);
style.setFont(font);
for (int i = 0; i < 10000; i++) {
    Row row = sheet.createRow(i);
    Cell cell = row.createCell((short) 0);
    cell.setCellStyle(style);
}

无论如何,你也可以试试这个:

org.apache.poi.hssf.usermodel.HSSFOptimiser.optimiseCellStyles(HSSFWorkbook)
于 2014-12-04T18:35:57.830 回答
0

根据我对数组的经验,当你得到一个OutOfBounds异常时,通常是因为我“溢出”了数组——也就是说,我循环的次数比索引中的项目总数多一个。这通常会发生,因为我忘记了当数组从 0 开始时,我必须只循环到数组长度 - 1。

确保您没有循环超过数组的长度。

于 2012-12-17T20:59:17.080 回答