2017-06-14 51 views
0

我正嘗試從REST端點下載csv文件。這是我正在嘗試的。Java:使用REST服務下載CSV文件

@ApiOperation(value = "export", 
     notes = "Export Cache details for a given criteria") 
@ApiImplicitParams({ 

}) 
@ApiResponses(value = { 
     @ApiResponse(code = 400, message = "Bad Request"), 
     @ApiResponse(code = 404, message = "Not Found"), 
     @ApiResponse(code = 500, message = "Internal Server Error") }) 
@RequestMapping(method = RequestMethod.GET, value = "/export") 
public ResponseEntity export(HttpServletRequest request) 
{ 
    CacheDataManager cacheResultHandler = new CacheDataManager(); 
    InputStreamResource inputStreamResource = null; 
    HttpHeaders httpHeaders = new HttpHeaders(); 
    long contentLengthOfStream; 

    try 
    { 
     inputStreamResource = cacheResultHandler.exportCacheResults(request); 
     httpHeaders.set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + "test.csv"); 

     contentLengthOfStream = inputStreamResource.contentLength(); 
     httpHeaders.setContentLength(contentLengthOfStream); 
    } 
    catch (IOException e) 
    { 
     e.printStackTrace(); 
    } 

    return new ResponseEntity(inputStreamResource, httpHeaders, HttpStatus.OK); 

} 

我的導出功能。

@Override 
public InputStreamResource export(HttpServletRequest request) 
{ 
    StringBuilder sb = new StringBuilder(); 
    StringBuilder fileName = new StringBuilder(VALIDATION_REPORT); 

    sb.append("Column A"); 
    sb.append(","); 
    sb.append("Column B"); 
    sb.append("\n"); 

    try 
    { 

      sb.append("TEST A"); 
      sb.append(','); 
      sb.append("TEST B"); 
      sb.append('\n'); 



     fileName.append("_").append(sdf.format(new Date())).append(".csv"); 
     return CsvFileWriter.csvFileWrite(fileName.toString(), sb); 

    } 
    catch (Exception e) 
    { 
     e.printStackTrace(); 

    } 

    return null; 
} 

CsvFileWriter.java

package it.app.ext.dashboard.util; 

import org.springframework.core.io.InputStreamResource; 

import java.io.*; 

public class CsvFileWriter 
{ 

public static InputStreamResource csvFileWrite(String fileName, StringBuilder content) throws FileNotFoundException 
{ 
    File file = null; 
    PrintWriter pw = null; 
    try 
    { 
     file = new File(fileName); 
     pw = new PrintWriter(file); 
     pw.write(content.toString()); 
    } 
    catch (FileNotFoundException e) 
    { 
     e.printStackTrace(); 
    } 
    finally 
    { 
     pw.flush(); 
     pw.close(); 
    } 

    InputStream inputStream = new FileInputStream(file); 

    return new InputStreamResource(inputStream); 
} 

}

文件與的tomcat/bin中文件夾內的內容產生,但發生的異常。

java.lang.IllegalStateException: InputStream has already been read - do not use InputStreamResource if a stream needs to be read multiple times. 

我想在調用此端點時下載.csv文件。

任何建議表示讚賞。

感謝您

回答

3

解釋相關:

你得到的inputStream第一:

contentLengthOfStream =inputStreamResource.contentLength();

然後Spring的returnValueHandlers再次獲得inputStream:

new ResponseEntity(inputStreamResource, httpHeaders, HttpStatus.OK)

但通過的InputStreamResource包裹InputStream中只能使用一次:

/** 
* This implementation throws IllegalStateException if attempting to 
* read the underlying stream multiple times. 
*/ 
public InputStream getInputStream() throws IOException, IllegalStateException { 
    if (this.read) { 
     throw new IllegalStateException("InputStream has already been read - " + 
       "do not use InputStreamResource if a stream needs to be read multiple times"); 
    } 
    this.read = true; 
    return this.inputStream; 
} 

解決方案:您可以從得到的inputStream字節,字節與返回ResponseEntity。

@ApiOperation(value = "export", 
     notes = "Export Cache details for a given criteria") 
@ApiImplicitParams({ 

}) 
@ApiResponses(value = { 
     @ApiResponse(code = 400, message = "Bad Request"), 
     @ApiResponse(code = 404, message = "Not Found"), 
     @ApiResponse(code = 500, message = "Internal Server Error") }) 
@RequestMapping(method = RequestMethod.GET, value = "/export") 
public ResponseEntity export(HttpServletRequest request) 
{ 
    CacheDataManager cacheResultHandler = new CacheDataManager(); 
    InputStreamResource inputStreamResource = null; 
    InputStream inputStream = null; 
    byte[] byteArray = new byte[0]; 
    HttpHeaders httpHeaders = new HttpHeaders(); 

    try 
    { 
     inputStreamResource = cacheResultHandler.exportCacheResults(request); 
     httpHeaders.set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + "test.csv"); 

     //convert inputStream to bytes 
     inputStream = inputStreamResource.getInputStream(); 
     ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 
     int nRead; 
     byte[] data = new byte[1024]; 
     while ((nRead = inputStream.read(data, 0, data.length)) != -1) { 
      buffer.write(data, 0, nRead); 
     } 

     buffer.flush(); 
     byteArray = buffer.toByteArray(); 

     httpHeaders.setContentLength(byteArray.length); 
    } 
    catch (IOException e) 
    { 
     e.printStackTrace(); 
    } 

    return new ResponseEntity(byteArray, httpHeaders, HttpStatus.OK); 

} 

建議:使用Apache Commons IO把InputStream轉化到bytes.Need添加一個lib依賴,它可以使你的代碼簡短

byte[] byteArray = IOUtils.toByteArray(inputStream); 
+0

這個工程ans響應正文包含** Response Body 下載exportCacheResults?pr = HTL&index = 0&size = 100 **。一旦點擊這個URL,它下載一個文件名** application-octet-stream-exportCacheResults -pr = HTL&index = 0&size = 100-blob-http --- localhost -8080-d541c19c-6da3-478e-b8ee-0448aa5bf598 * *。這是一個** File **類型的文件。如何下載.csv文件 – Rose18

+2

我看不到任何與您的url相關的代碼「exportCacheResults?pr = HTL&index = 0&size = 100」。當添加'httpHeaders.set(「Content-Disposition」,「attachment; filename =」+「test.csv」)'時,您可以直接下載.csv文件! – lihongxu

0

不使用相同的文件兩次,使用單獨的代碼返回的InputStream:

return new InputStreamResource(new FileInputStream(new File(fileName)));

+0

我改變了這些**的InputStream的inputStream =新的FileInputStream(文件);返回新的InputStreamResource(inputStream); **兩行代碼段。但是錯誤和以前一樣。 – Rose18

+0

@ Rose18 new應創建文件對象實例: 'InputStream inputStream = new FileInputStream(new File(fileName))' 而不是重新使用舊文件對象 –

+0

抱歉,我沒有得到你所說的。我需要更改哪個文件? – Rose18