天天看點

【小坑】java下載下傳excel檔案

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檔案,報錯提示:

【小坑】java下載下傳excel檔案
【小坑】java下載下傳excel檔案

按文中辦法添加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讀取的問題

【小坑】java下載下傳excel檔案

由提示資訊得知:這個問題報的是格式或擴充名的問題。而擴充名是沒有問題了,經檢查發現是格式的問題,本地調試的時候讀取的是正确完整的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實作點選按鈕,下載下傳檔案)