2013-04-03 34 views
27

我有一個web服務調用,通過它可以上傳zip文件。這些文件然後被轉發到另一個服務進行存儲,解壓縮等。 現在,文件存儲在文件系統中,然後構建FileSystemResource。如何使用RestTemplate轉發大文件?

Resource zipFile = new FileSystemResource(tempFile.getAbsolutePath()); 

我可以用一個ByteStreamResource爲了節省時間(磁盤上的文件的保存轉發之前沒有必要),但我需要建立一個字節數組。在大文件的情況下,我會得到一個「OutOfMemory:java堆空間」錯誤。

ByteArrayResource r = new ByteArrayResource(inputStream.getBytes()); 

的任何解決方案,以轉發文件沒有得到使用RestTemplate的內存不足的錯誤?

+0

燦你是否將輸入流傳遞給其他服務?或者您必須將輸入流寫入文件,然後將文件句柄傳遞給服務。另外,不確定這與Groovy有何關係? –

+0

我沒有找到任何方法來傳遞輸入流。我使用Groovy標籤,因爲代碼是在groovy中(java InputStream沒有getBytes方法) –

+1

啊,我是在用Java風格編寫時拋出的;-)那麼這個其他服務接受了什麼呢? –

回答

32

您可以使用execute進行此類低級操作。在這個片段中,我使用了Commons IO的copy方法來複制輸入流。您需要自定義HttpMessageConverterExtractor以獲得您期待的響應。

final InputStream fis = new FileInputStream(new File("c:\\autoexec.bat")); // or whatever 
final RequestCallback requestCallback = new RequestCallback() { 
    @Override 
    public void doWithRequest(final ClientHttpRequest request) throws IOException { 
     request.getHeaders().add("Content-type", "application/octet-stream"); 
     IOUtils.copy(fis, request.getBody()); 
    } 
}; 
final RestTemplate restTemplate = new RestTemplate(); 
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); 
requestFactory.setBufferRequestBody(false);  
restTemplate.setRequestFactory(requestFactory);  
final HttpMessageConverterExtractor<String> responseExtractor = 
    new HttpMessageConverterExtractor<String>(String.class, restTemplate.getMessageConverters()); 
restTemplate.execute("http://localhost:4000", HttpMethod.POST, requestCallback, responseExtractor); 

(感謝巴茲的指出你需要調用setBufferRequestBody(false)或將擊敗點)

+0

是不是所有的輸入流都以這種方式加載到內存中? – Bax

+2

@Bax不,在複製過程中它會被零碎地裝入。應該是相當有記憶效率的。 – artbristol

+0

doWithRequest(request)在request.execute()之前被調用,並且在所有流被複制到請求主體之前它不會返回。 cintent被大塊複製到身體上,但沒有人從它身上消耗掉,它不像管子那樣起作用,我是否錯過了smth? – Bax

8

的唯一部分@ artbristol的answer你真正需要的是這樣的(你可以設置爲RestTemplate的Spring bean):

final RestTemplate restTemplate = new RestTemplate(); 
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); 
requestFactory.setBufferRequestBody(false);  
restTemplate.setRequestFactory(requestFactory);  

在那之後,我覺得只是使用FileSystemResource作爲您的要求的身體會做正確的事。

我也用這種方式成功地使用了InputStreamResource,對於已經有數據作爲InputStream並且不需要多次使用它的情況。

在我的情況下,我們gzipped我們的文件,並在InputStreamResource包裝GZipInputStream

9

我認爲上面的答案有不必要的代碼 - 你不需要創建一個匿名的RequestCallback內部類,並且你不需要使用來自apache的IOUtils。

我花了一點時間研究一個類似的解決方案,以你的,這是我想出了:

你可以實現你的目標,多用the Spring Resource Interface和RestTemplate簡單。

RestTemplate restTemplate = new RestTemplate(); 

SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); 
requestFactory.setBufferRequestBody(false); 
restTemplate.setRequestFactory(requestFactory); 

File file = new File('/whatever') 

ResponseEntity e = restTemplate.exchange("http://localhost:4000", HttpMethod.POST, new HttpEntity<Resource>(new FileSystemResource(file)), Map.class); 

(這個例子假定從那裏你要發佈帖子的迴應是JSON。但是,這可以很容易地通過改變返回類型類...設置上面Map.class改變)

相關問題