2013-04-03 22 views
27

Zip dosyalarının yüklenebileceği bir web servis çağrısı var. Dosyalar daha sonra depolama, unzipping, vb. Için başka bir servise iletilir. Şu an için dosya dosya sisteminde saklanır, daha sonra bir FileSystemResource oluşturulur.Büyük dosyalar RestTemplate ile nasıl iletilir?

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

Zamanım (yönlendirmeden önce gerekli değildir diskteki dosyanın tasarrufu) kurtarmak için bir ByteStreamResource kullanabilirsiniz ama bunun için ben bir bayt dizisi oluşturmak gerekiyor. Büyük dosyalar durumunda "OutOfMemory: java yığın alanı" hatası alıyorum.

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

RestTemplate kullanarak OutOfMemory hata almadan dosyaları yönlendirmekle Herhangi çözümler?

+0

Can (Bu örnek Gönderide yerden tepki JSON olduğunu. Ama, bu kolayca döndürme türü sınıfını ... Yukarıda Map.class ayarlı değiştirerek değiştirilebilir varsayar) Giriş akışını diğer servise mi geçiriyorsunuz? Veya giriş akışını bir dosyaya yazmanız ve ardından dosya tanıtıcısını servise iletmeniz gerekir. Ayrıca, bunun Groovy ile nasıl bağlantılı olduğundan emin değil misiniz? –

+0

Sadece giriş akışını geçmek için bir yol bulamadım. Kod groovy (java InputStream bir getBytes yöntemi yok) –

+1

Ahhh, çok Java tarzında yazarken atıldı çünkü Groovy etiketini kullandım ;-) SO bu diğer hizmet sonra ne kabul eder? –

cevap

32

Bu tür düşük düzey işlemler için execute kullanabilirsiniz. Bu snippet'te giriş akışını kopyalamak için Commons IO'nun copy yöntemini kullandım. Beklediğiniz türde bir yanıt için HttpMessageConverterExtractor'u özelleştirmeniz gerekir.

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); 

(işaret için Baz sayesinde size setBufferRequestBody(false) çağırmanız gerekir yoksa noktasını yeneceğiz)

+0

Girdi akışı tüm belleğe bu şekilde yüklenmemiş mi? – Bax

+2

@Bax Hayır, kopyalama sırasında parça parça yüklenir. Oldukça bellek verimli olmalı. – artbristol

+0

doWithRequest (istek) request.execute() 'den önce çağrılır ve tüm akış istek gövdesine kopyalanana kadar geri dönmez. Cintent, vücuttaki parçalara kopyalanır, fakat kimse onu tüketmez, pipo gibi davranmaz, saçmalamıyorum? – Bax

8

sadece bir kısmını @ artbristol en answer gerçekten ihtiyacınız bu bir olarak ayarlayabilirsiniz hangi (olduğu RestTemplate Bahar fasulye): Bundan sonra

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

, sadece doğru olanı yapacağız isteğiniz organı olarak bir FileSystemResource kullanarak düşünüyorum.

Ayrıca, InputStream numaralı verilere sahip olduğunuz ve birden çok kez tüketmeye gerek duymadığınız durumlar için, bu şekilde InputStreamResource'u da başarıyla kullandım.

Durumumda, dosyalarımızı gzipledik ve bir GZipInputStream bir InputStreamResource ürününe sardık.

9

Yukarıdaki cevabın gereksiz bir kod olduğunu düşünüyorum - anonim bir RequestCallback iç sınıfı yapmanıza gerek yoktur ve Apache'den IOUtils kullanmanız gerekmez.

ben sizinkine benzer bir çözüm araştıran biraz zaman geçirdim ve bu ile geldi budur: Sen the Spring Resource Interface ve RestTemplate kullanarak hedef çok daha basit başarabilirsiniz

.

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);