web-dev-qa-db-fra.com

Comment transférer des fichiers volumineux avec RestTemplate?

J'ai un appel de service Web via lequel les fichiers Zip peuvent être téléchargés. Les fichiers sont ensuite transmis à un autre service pour le stockage, la décompression, etc. Pour l'instant, le fichier est stocké sur le système de fichiers, puis un FileSystemResource est construit.

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

Je pourrais utiliser un ByteStreamResource afin de gagner du temps (la sauvegarde du fichier sur le disque n'est pas nécessaire avant le transfert) mais pour cela j'ai besoin de construire un tableau d'octets. En cas de fichiers volumineux, j'obtiendrai une erreur "OutOfMemory: Java heap space").

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

Des solutions pour transférer des fichiers sans obtenir une erreur OutOfMemory en utilisant RestTemplate?

36
Gabi

Vous pouvez utiliser execute pour ce type d'opération de bas niveau. Dans cet extrait, j'ai utilisé la méthode copy de Commons IO pour copier le flux d'entrée. Vous devrez personnaliser le HttpMessageConverterExtractor pour le type de réponse que vous attendez.

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

(Merci à Baz d'avoir souligné que vous devez appeler setBufferRequestBody(false) ou cela vaincra le point)

37
artbristol

Je pense que la réponse ci-dessus contient du code inutile - vous n'avez pas besoin de créer une classe interne RequestCallback anonyme, et vous n'avez pas besoin d'utiliser IOUtils d'Apache.

J'ai passé un peu de temps à rechercher une solution similaire à la vôtre et voici ce que j'ai trouvé:

Vous pouvez atteindre votre objectif beaucoup plus simplement en utilisant l'interface de ressource Spring et RestTemplate.

RestTemplate restTemplate = new RestTemplate();

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

File file = new File("/whatever");

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

(Cet exemple suppose que la réponse à partir de laquelle vous postez est JSON. Mais, cela peut facilement être modifié en changeant la classe de type de retour ... définie sur Map.class ci-dessus)

15
RuntimeBlairror

La seule partie de @ artbristol réponse dont vous avez vraiment besoin est celle-ci (que vous pouvez configurer en tant que RestTemplate Spring bean):

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

Après cela, je pense que l'utilisation d'un FileSystemResource comme corps de votre requête fera la bonne chose.

J'ai également utilisé un InputStreamResource avec succès de cette façon, pour les cas où vous avez déjà les données en tant que InputStream et n'avez pas besoin de les consommer plusieurs fois.

Dans mon cas, nous avions compressé nos fichiers et enveloppé un GZipInputStream dans un InputStreamResource.

14
Ed Brannin