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實作點選按鈕,下載下傳檔案)