在项目中,对 Excel 的操作,我们一般都会使用 POI 这个工具包。而这个工具包也在不断的优化,所以会存在很多的版本,那么在 MAVEN 项目中,经常会引入不同的依赖 ,所以会在不经意间引入不同版本的依赖,导致正常运行的项目突然之间抛出很多没见过的异常。而这篇文章内容就是根据所遇而写的…

POI 依赖引入

我们经常会使用 POI 对数据表的导入导出进行操作,而这个工具包无疑是最合适的。每次的更新都能提供更好的性能。
所使用的的依赖如下:

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.10-FINAL</version>
</dependency>

<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.10-FINAL</version>
</dependency>

多版本 Excel 工具类实例化

当然我使用的并不是最新的内容。
很早之前我们使用 POI 工具包实例化针对于不同版本的 Excel 的对象,如:

1
2
3
4
5
6
7
8
9
//针对于03版本的Excel,实例化对象
POIFSFileSystem pfs = new POIFSFileSystem(new FileInputStream(file));
HSSFWorkbook hwb = new HSSFWorkbook(pfs);

//针对于07版本的Excel,实例化对象
XSSFWorkbook xw = new XSSFWorkbook(file);

//兼容多个Excel版本的实例化对象,最方便,可以完成多个后缀的读写 .xls || .xlsx
Workbook workbook = WorkbookFactory.create(new FileInputStream(file));

项目中使用:

1
SXSSFWorkbook wb = new SXSSFWorkbook(100);

无疑,我一般使用的肯定是第三种
我们先看看报了什么错…

报错信息

测试环境:
1
2
3
4
Caused by: java.lang.RuntimeException: java.io.IOException: No such file or directory
at org.apache.poi.xssf.streaming.SXSSFWorkbook.createAndRegisterSXSSFSheet(SXSSFWorkbook.java:640)
at org.apache.poi.xssf.streaming.SXSSFWorkbook.createSheet(SXSSFWorkbook.java:657)
at org.apache.poi.xssf.streaming.SXSSFWorkbook.createSheet(SXSSFWorkbook.java:71)

没有这个文件或目录?不可能,这个目录是存在的…

开发及本地:
1
2
3
4
5
6
7
Caused by: java.io.IOException: Zip bomb detected! The file would exceed the max. ratio of compressed file size to the size of the expanded data. This may indicate that the file is used to inflate memory usage and thus could pose a security risk. You can adjust this limit via ZipSecureFile.setMinInflateRatio() if you need to work with files which exceed this limit. Counter: 172032, cis.counter: 1716, ratio: 0.009974888392857142Limits: MIN_INFLATE_RATIO: 0.01
at org.apache.poi.openxml4j.util.ZipSecureFile$ThresholdInputStream.advance(ZipSecureFile.java:258)
at org.apache.poi.openxml4j.util.ZipSecureFile$ThresholdInputStream.read(ZipSecureFile.java:215)
at java.io.FilterInputStream.read(FilterInputStream.java:107)
at org.apache.poi.xssf.streaming.SXSSFWorkbook.copyStream(SXSSFWorkbook.java:386)
at org.apache.poi.xssf.streaming.SXSSFWorkbook.injectData(SXSSFWorkbook.java:368)
at org.apache.poi.xssf.streaming.SXSSFWorkbook.write(SXSSFWorkbook.java:947)

压缩比?没用到压缩这个玩意儿啊…

内心独白

咦!!!
同样的代码,不同的错误信息?
怎么搞得?
难道是测试环境没给写的权限?
不对啊,之前都是正常的啊,这个代码大半年都没动了,难道是有人把权限给改动了?
会不会是我?这段时间我一直都是在弄 linux 相关的学习,会不会给误点了?先不管了,先看看本地为什么会报错吧…

错误排查

经过一番的心理斗争,还是默默的去找原因,经过我代码排查,找到了是在写流的时候报的错,代码:

1
2
3
4
// 输出流
FileOutputStream os = new FileOutputStream("test.xlsx");
//excel---这个地方报错了
workbook.write(os);

奇怪了,怀疑可能是包的问题,先查查用了哪些包吧,经过查找,发现在 pom.xml 中只引用了 3.10-FINAL 版本的 POI 包。
奇怪了,找到实例化的工厂对象,看看到哪个地方去了。通过实例化的方法,去查,发现是进入了 3.10-FINAL 版本的。

还是采用查找类路径的方法吧,这么一查,发现还有一个 3.14 版本的 POI。好吧,我在两个版本的构造方法都打上断点,很神奇的发现,它居然跳到了 3.14 版本的类中,实例化了 3.14 版本的 SXSSFWorkbook 实例。

神奇了,编程工具中的 依赖结构查询 没发现有 3.14 版本的,为啥就跑过去了?
查找 pom.xml 看是不是我无意中弄进去了,然而通过工程的 pom.xml 并没有发现。所以只能使用最笨的方式了,一个一个依赖的找,最终发现是我在写单元测试的时候引入一个包导致的:

1
2
3
4
5
6
<dependency>
<groupId>org.dbunit</groupId>
<artifactId>dbunit</artifactId>
<version>2.5.4</version>
<scope>test</scope>
</dependency>

进入这个依赖发现这里边居然有依赖 POI 相关的包,就是 3.14 版本的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.14</version>
<exclusions>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.14</version>
</dependency>

问题解决

额好吧,它自己引入的,那我引入 dbunit 这个依赖的时候就去掉就是了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<dependency>
<groupId>org.dbunit</groupId>
<artifactId>dbunit</artifactId>
<version>2.5.4</version>
<exclusions>
<exclusion>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>

打包…
再测试,正常了…
上测试环境,居然也正常了…

总结

在开发的时候,总会因为需要而引入不同的依赖,而每次引入依赖的时候,没有仔细的去检查这个依赖中时候存在和当前项目所使用的依赖有冲突的依赖版本,导致了因版本冲突而使代码抛出异常。

参考

1.我在CSND写的DEMO:https://blog.csdn.net/maiyikai/article/details/70331798

最后更新: 2019年10月12日 20:21

原始链接: https://maiyikai.github.io/2019/09/12/1568191417/

× ~谢谢大爷~
打赏二维码