关于原版poi中的一个bug及解决方案

来源:互联网 发布:剑灵天空拳套数据 编辑:程序博客网 时间:2024/05/12 05:11

问题呈现:
        用户在“开发工具—通用码表分类”中进入任意明细,点击“Excel导出”,之后清空明细表,将导出的文件进行“Excel导入”操作时(这种情况在现实使用中并非不会发生,如用户将之前导出的文件作为备份重新导入到系统中),如果导入的码表中存在上级,那么导入的内容会有错误(“上级名称”列读取不到,默认为空),并且后台会报出类似下面的警告:


问题解析:
        现已查明该问题是由于导出的Excel文件存在问题导致的,而导出的文件存在问题根本上是由于apache的poi.jar存在bug造成的,具体原因如下:
        在通过poi进行Excel导出操作时,poi在将内容写入单元格的过程中,会将表格的维度(Dimension,即表格的区域,如7×19)信息通过org.apache.poi.hssf.record包中的DimensionRecord类时时写入到Excel文件的二进制信息中,以便该文件在被读取时使用。但是在poi中真正调用DimensionRecord类的地方是org.apache.poi.hssf.model.Sheet类中的addValueRecord方法,在该方法中存在一个条件判断错误(第956行),详细代码为:

DimensionsRecord d = (DimensionsRecord)this.records.get(getDimsLoc());if (col.getColumn() > d.getLastCol()) {d.setLastCol((short)(col.getColumn() + 1));}
        由于Excel中的内容是逐列(Column)进行读取的,这就导致LastCol以2为公差增长,而LastCol的值直接决定了Dimension中所存入的表格列数,具体情形如下:
表格总列数DimensionRecord中记录的列数前台读取到的列数后台是否报错

1

1

1

2

1

1

3

3

3

4

3

3

5

5

5

6

5

5

7

7

7

8

7

7

9

9

9

        即当表格总列数为奇数列时,导出的文件不会出错,而如果导出的文件为偶数列时,导出的文件会出错。由于“通用码表”模块在进行需求修改之后将之前的“唯一标识”列删除,所有表格由之前的9列变成8列,这也就是为什么在调整之前后台不会报错,而调整之后后台会报错的原因。
        正确的代码应将if (col.getColumn() > d.getLastCol())修改为if (col.getColumn() >= d.getLastCol()),这一点已经得到apache官方的证实,详情请参考:
       
https://issues.apache.org/bugzilla/show_bug.cgi?id=53414
        http://mail-archives.apache.org/mod_mbox/poi-commits/201206.mbox/%3C20120626113047.F047C238890B@eris.apache.org%3E

 

解决方案:

        由于这个问题apache官方在今年6月26日才给出解决策略,而最新版的poi(poi-bin-3.8-beta5-20111217.jar)还是去年年底更新的,所以这个问题现在暂时无法通过升级poi来解决(猜测下个版本可能会有所修改),可下载poi的源代码按照官方给出的方案(即同上方案)进行修改后生成jar来替换之前的poi。这种方案简单易行,相对比较安全,但可能不利于对poi的版本进行定义,给系统移植带来一点小麻烦。
        下载地址为
http://archive.apache.org/dist/poi/dev/src/

原创粉丝点击