最近使用Apache poi 做excel導出的功能,遇到了如下問題:
Your stream was neither an OLE2 stream, nor an OOXML stream
起初對比其他的web工程,沒有發現如何解決。最後找到拋出此異常的源碼:
org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java:75)
public static Workbook create(InputStream inp) throws IOException, InvalidFormatException {
if (!((InputStream)inp).markSupported()) {
inp = new PushbackInputStream((InputStream)inp, 8);
}
if (POIFSFileSystem.hasPOIFSHeader((InputStream)inp)) {
return new HSSFWorkbook((InputStream)inp);
} else if (POIXMLDocument.hasOOXMLHeader((InputStream)inp)) {
return new XSSFWorkbook(OPCPackage.open((InputStream)inp));
} else {
throw new IllegalArgumentException("Your InputStream was neither an OLE2 stream, nor an OOXML stream");
}
}
可以看到,在調用WorkbookFactory.create(inputStream)
來創建Workbook時,會根據文件類型(文件頭)來區別、創建合適的Workbook對象。如果不滿足前兩個if條件裏的hasPOIFSHeader()
方法,就會拋出異常。而兩個if裏的hasPOIFSHeader()方法就是針對Excel2003和Excel2007的判斷,讀取文件流中的文件頭(byte[8])信息去判斷。
那既然是根據文件的頭部信息去比對進行判斷的,並且excel只有2003和2007兩個版本,那爲什麼放在classpath下的excel模板讀取後創建WorkBook時,文件header判斷都不符合呢?
最後找到原因:maven編譯打包時,將resources下的資源文件轉碼了。最終web工程打出的jar/war包,裏面歸檔進去的excel模板文件都是亂碼,文件頭信息被修改,導致poi根本無法識別這樣的excel文件。
解決辦法:
項目的pom.xml中添加maven資源插件
<plugins>
<!-- 讓maven不編譯xls文件,但仍將其打包 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>xls</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>
</plugins>
總結
1、推薦使用poi-ooxml中的WorkbookFactory.create(inputStream)
來創建Workbook,因爲HSSFWorkbook和XSSFWorkbook都實現了Workbook接口。(Excel2003和Excel2007兩個版本在此通過文件header進行適配)
2、當你的工程中,需要放入一些靜態資源文件作爲模板,比如excel填充模板,word模板(裏面有些固定樣式,程序運行時用模板導出報表類的),這個時候,最好都配置maven去除資源文件不被轉碼。下面的鏈接有2種方式。
Maven 打包 過濾資源文件
https://blog.csdn.net/qing_mei_xiu/article/details/80661216
我的簡書:https://www.jianshu.com/u/dd8907cc9fa5
歡迎來踩