web-dev-qa-db-fra.com

Comment utiliser par programme un fichier à partir d'une API Rest utilisant Spring?

J'ai la ressource Reste suivante qui télécharge un fichier à partir de DB. Cela fonctionne bien à partir du navigateur, cependant, lorsque j'essaie de le faire à partir d'un client Java, comme indiqué ci-dessous, je reçois le code 406 (erreur non acceptée).

...
 @RequestMapping(value="/download/{name}", method=RequestMethod.GET, 
        produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public @ResponseBody HttpEntity<byte[]> downloadActivityJar(@PathVariable String name) throws IOException
{
    logger.info("downloading : " + name + " ... ");
    byte[] file = IOUtils.toByteArray(artifactRepository.downloadJar(name));
    HttpHeaders header = new HttpHeaders();
    header.set("Content-Disposition", "attachment; filename="+ name + ".jar");
    header.setContentLength(file.length);

    return new HttpEntity<byte[]>(file, header);
}
...

Le client est déployé sur le même serveur avec un port différent (le message donne le nom correct):

    ...
    RestTemplate restTemplate = new RestTemplate();
    String url = "http://localhost:8080/activities/download/" + message.getActivity().getName();
    File jar = restTemplate.getForObject(url, File.class);
    logger.info("File size: " + jar.length() + " Name: " + jar.getName());
    ...

Qu'est-ce que j'oublie ici?

6
Sami

Le code de réponse est 406 Non accepté. Vous devez spécifier un en-tête de demande 'Accepter' qui doit correspondre au champ 'produit' de votre RequestMapping.

RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new ByteArrayHttpMessageConverter());    
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM));
HttpEntity<String> entity = new HttpEntity<String>(headers);

ResponseEntity<byte[]> response = restTemplate.exchange(URI, HttpMethod.GET, entity, byte[].class, "1");

if(response.getStatusCode().equals(HttpStatus.OK))
        {       
                FileOutputStream output = new FileOutputStream(new File("filename.jar"));
                IOUtils.write(response.getBody(), output);

        }

Un petit avertissement: ne faites pas cela pour les gros fichiers. RestTemplate.exchange (...) charge toujours l'intégralité de la réponse en mémoire afin que vous puissiez obtenir des exceptions OutOfMemory. Pour éviter cela, n'utilisez pas Spring RestTemplate, mais utilisez directement le standard Java HttpUrlConnection ou les composants http Apache.

18
Geert Pante

essayez peut-être ceci, changez votre méthode de repos en tant que telle:

public javax.ws.rs.core.Response downloadActivityJar(@PathVariable String name) throws IOException {
    byte[] file = IOUtils.toByteArray(artifactRepository.downloadJar(name));
    return Response.status(200).entity(file).header("Content-Disposition", "attachment; filename=\"" + name + ".jar\"").build();
}

En outre, utilisez quelque chose comme ceci pour télécharger le fichier, vous le faites mal.

org.Apache.commons.io.FileUtils.copyURLToFile(new URL("http://localhost:8080/activities/download/" + message.getActivity().getName()), new File("locationOfFile.jar"));

Vous devez lui dire où enregistrer le fichier, l'API REST ne le fera pas pour vous, je ne pense pas.

3
Triton Man

Vous pouvez utiliser InputStreamResource avec ByteArrayInputStream.

@RestController
public class SomeController {
    public ResponseEntity<InputStreamResource> someResource() {
         byte[] byteArr = ...;
         return ResponseEntity.status(HttpStatus.OK).body(new InputStreamResource(new ByteArrayInputStream(byteArr)));
    }
}
1
marknorkin

Essayez d'utiliser la méthode execute sur RestTemplate avec ResponseExtractor et lisez les données du flux à l'aide de l'extracteur.

0
Rafal G.

Utilisez ceci pour télécharger une image JPEG en utilisant Exchange. Cela fonctionne parfaitement.

URI uri = new URI(packing_url.trim());

HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.IMAGE_JPEG));
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);

// Send the request as GET
ResponseEntity<byte[]> result= template.exchange(uri, HttpMethod.GET, entity, byte[].class);

out.write(result.getBody());
0
Rohit Ahuja