excel文件的導入導出是很常見的功能,這次做了個下載的功能,踩了一些坑,記下來避免以后重復踩……
1、inputstream序列化問題
Could not write JSON document: No serializer found for class java.io.FileDescriptor and no properties discovered to create BeanSerializer
客戶端調取服務端上傳,從前台獲取的file文件中拿到inputstream,做一些判斷后(格式校驗、大小校驗等)將inputstream作為參數傳給服務端報如下錯誤:
Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON document: No serializer found for class java.io.FileDescriptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
因為輸入流InputStream序列化錯誤。計算機傳輸數據實際上是二進制的傳輸,將inputstream轉化為字節數組就可以通過網絡流進行傳輸了,使用byte[] 來替代InputStream。
2、讀取resources下的xlsx文件
將xlsx文件放項目resources目錄下,通過以下代碼本地調試通過:
InputStream templateStream = ClassUtils.getDefaultClassLoader().getResourceAsStream(TEMPTALTE); int len = templateStream.available(); byte[] readBuf = new byte[len]; templateStream.read(readBuf, 0, len);
將inputstream讀入到readBuf里,再將readBuf傳給服務端。本地測試通過,放到測試環境,於是開始了填坑……
3、java.util.zip.ZipException: invalid stored block lengths
(參考:Poi讀取Excle報錯 java.util.zip.ZipException: invalid stored block lengths)
是因為打為jar包時對resources資源文件進行了轉碼壓縮,直接讀取inputstream使用無法識別。將jar包解壓縮,打開里面的xlsx文件,報錯提示:
按文中辦法添加maven插件,打包時對xls和xlsx文件不進行轉碼壓縮。
<plugin> <groupId>org.apache.maven.plugins</groupId> <version>2.6</version> <artifactId>maven-resources-plugin</artifactId> <configuration> <encoding>UTF-8</encoding> <nonFilteredFileExtensions> <nonFilteredFileExtension>xlsx</nonFilteredFileExtension><!--xlsx結尾的文件不壓縮--> </nonFilteredFileExtensions> </configuration> </plugin>
添加排除xlsx打包壓縮之后,從打完的jar包解壓縮出的xlsx可以正常打開。
4、read讀取的問題
由提示信息得知:這個問題報的是格式或擴展名的問題。而擴展名是沒有問題了,經檢查發現是格式的問題,本地調試的時候讀取的是正確完整的byte[]數據,測試環境讀取的不全或沒有讀取數據。
查看inputstream的 read(byte b[], int off, int len) 方法
* Reads up to <code>len</code> bytes of data from the input stream into
* an array of bytes. An attempt is made to read as many as
* <code>len</code> bytes, but a smaller number may be read.
* The number of bytes actually read is returned as an integer.
修改如下:
InputStream templateStream = ClassUtils.getDefaultClassLoader().getResourceAsStream(TEMPLATE); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[2048]; int num = -1; while((num = templateStream.read(buffer)) != -1){ baos.write(buffer, 0, num); } baos.flush(); baos.toByteArray(); baos.close();
5、excel單元格包含換行
讀取excel到json,然后通過fastjson反序列化為list對象。當excel單元格包含換行符時報錯:(參考:用java導入導出excel如何去掉軟回車和硬回車)
Illegal unquoted character ((CTRL-CHAR, code 10)): has to be escaped using backslash to be included in string value excel
一種方法是替換掉excel的特殊字符
for(int i=10;i<14;i++) { str = str.replaceAll(String.valueOf((char)i), ""); }
另一種方法是正則替換
//空格\t、回車\n、換行符\r、制表符\t Pattern p = Pattern.compile("\\s*|\t|\r|\n"); Matcher m = p.matcher(str); dest = m.replaceAll("");
6、ajax下載
由於ajax函數的返回類型只有xml、text、json、html等類型,沒有“流”類型,所以通過ajax去請求該接口是無法下載。查看XHR,可以看到返回的報文體。
- window.open("下載文件的后端接口")
- 構建一個表單實現下載
(參考:JS實現點擊按鈕,下載文件)