2013-04-03 10 views
27

Mam połączenie z serwisem, za pomocą którego można przesyłać pliki zip. Pliki są następnie przekazywane do innej usługi do przechowywania, rozpakowywania itp. Na razie plik jest przechowywany w systemie plików, a następnie zbudowany jest obiekt FileSystemResource.Jak przekazywać duże pliki za pomocą narzędzia RestTemplate?

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

mogę użyć ByteStreamResource w celu zaoszczędzenia czasu (zapisywanie pliku na dysku nie jest potrzebne przed przekazaniem), ale za to muszę zbudować tablicę bajtów. W przypadku dużych plików otrzymam komunikat "OutOfMemory: java heap space".

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

Jakieś rozwiązanie przekazywania plików bez uzyskania błędu OutOfMemory za pomocą RestTemplate?

+0

Can przekazujesz strumień wejściowy do innej usługi? Albo będziesz musiał napisać strumień wejściowy do pliku, a następnie przekazać uchwyt pliku do usługi. Ponadto, nie wiesz, jak to się ma do Groovy? –

+0

Nie znalazłem sposobu, aby po prostu przekazać strumień wejściowy. Użyłem tagu Groovy, ponieważ kod jest w groovy (java InputStream nie ma metody getBytes) –

+1

Ahhh, zostałem rzucony, gdy piszesz to w bardzo stylu Java ;-) A zatem, co akceptuje ta druga usługa? –

Odpowiedz

32

Można użyć execute dla tego rodzaju operacji niskiego poziomu. W tym fragmencie użyłem metody Commons IO, aby skopiować strumień wejściowy. Będziesz musiał dostosować HttpMessageConverterExtractor, aby uzyskać oczekiwaną odpowiedź.

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

(dzięki Baz dla wskazując, trzeba zadzwonić setBufferRequestBody(false) lub będzie pokonać punkt)

+0

Czy strumień wejściowy nie jest załadowany do pamięci w ten sposób? – Bax

+2

@Bax Nie, będzie on ładowany fragmentarycznie podczas kopiowania. Powinien być dość efektywny pod względem pamięci. – artbristol

+0

DoWithRequest (request) jest wywoływane przed request.execute() i nie zostanie zwrócone, dopóki cały strumień nie zostanie skopiowany do treści żądania. Cintent jest kopiowany w kawałkach do ciała, ale nikt go nie zużywa, nie zachowuje się jak fajka, czy brakuje mi czegoś? – Bax

8

jedyną częścią @ artbristol na answer naprawdę potrzebne jest to (które można skonfigurować jako RestTemplate Wiosna fasola):

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

Po tym, myślę, że po prostu za pomocą FileSystemResource jako ciała żądanie będzie zrobić dobry uczynek.

W ten sposób z powodzeniem używam InputStreamResource, w przypadkach, w których dane są już zapisane jako InputStream i nie trzeba ich używać wielokrotnie.

W moim przypadku zapakowaliśmy nasze pliki do formatu gz i opakowaliśmy w InputStreamResource.

9

Myślę, że powyższa odpowiedź ma niepotrzebny kod - nie trzeba tworzyć anonimowej klasy wewnętrznej RequestCallback i nie trzeba używać IOUtils z apache.

Spędziłem trochę czasu na poszukiwania podobnego rozwiązania do Ciebie i to co wymyśliłem:

można osiągnąć swój cel znacznie prostsze przy użyciu the Spring Resource Interface i 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); 

(W tym przykładzie założono, że odpowiedź skąd Piszesz do JSON jest. Ale to można łatwo zmienić poprzez zmianę Zwraca typ klasy ... Zestaw do Map.class powyżej)

Powiązane problemy