web-dev-qa-db-fra.com

Comment renvoyer une image dans le contrôleur Spring Boot et servir comme un système de fichiers

J'ai essayé les différentes manières données dans Stackoverflow, peut-être que j'ai raté quelque chose.

J'ai un client Android (dont je ne peux pas changer le code) qui reçoit actuellement une image comme celle-ci:

HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.connect();

url est l'emplacement de l'image (ressource statique sur CDN). Mon point de terminaison Spring Boot API doit maintenant se comporter comme une ressource de fichier de la même manière afin que le même code puisse obtenir des images de l'API (Spring boot version 1.3.3).

J'ai donc ceci:

@ResponseBody
@RequestMapping(value = "/Image/{id:.+}", method = RequestMethod.GET, consumes = MediaType.ALL_VALUE, produces = MediaType.IMAGE_JPEG_VALUE)
public ResponseEntity<byte[]> getImage(@PathVariable("id")String id) {
    byte[] image = imageService.getImage(id);  //this just gets the data from a database
    return ResponseEntity.ok(image);
}

Maintenant, lorsque le code Android essaie d'obtenir http://someurl/image1.jpg J'obtiens cette erreur dans mes journaux:

Résolution de l'exception du gestionnaire [public org.springframework.http.ResponseEntity com.myproject.MyController.getImage (Java.lang.String)]: org.springframework.web.HttpMediaTypeNotAcceptableException: impossible de trouver une représentation acceptable

La même erreur se produit lorsque je branche http://someurl/image1.jpg dans un navigateur.

Curieusement, mes tests sont corrects:

Response response = given()
            .pathParam("id", "image1.jpg")
            .when()
            .get("MyController/Image/{id}");

assertEquals(HttpStatus.OK.value(), response.getStatusCode());
byte[] array = response.asByteArray(); //byte array is identical to test image

Comment puis-je faire en sorte que cela se comporte comme une image servie normalement? (Notez que je ne peux pas modifier l'en-tête de type de contenu que le code Android envoie)

MODIFIER

Code après les commentaires (définir le type de contenu, supprimer produces):

@RequestMapping(value = "/Image/{id:.+}", method = RequestMethod.GET, consumes = MediaType.ALL_VALUE)
public ResponseEntity<byte[]> getImage(@PathVariable("id")String id, HttpServletResponse response) {
    byte[] image = imageService.getImage(id);  //this just gets the data from a database
    response.setContentType(MediaType.IMAGE_JPEG_VALUE);
    return ResponseEntity.ok(image);
}

Dans un navigateur, cela semble simplement donner une ordure stringifiée (octet aux caractères, je suppose). Dans Android il ne fait pas d'erreur, mais l'image ne s'affiche pas.

14
Manish Patel

Enfin corrigé cela ... J'ai dû ajouter une ByteArrayHttpMessageConverter à ma sous-classe WebMvcConfigurerAdapter:

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    final ByteArrayHttpMessageConverter arrayHttpMessageConverter = new ByteArrayHttpMessageConverter();
    final List<MediaType> list = new ArrayList<>();
    list.add(MediaType.IMAGE_JPEG);
    list.add(MediaType.APPLICATION_OCTET_STREAM);
    arrayHttpMessageConverter.setSupportedMediaTypes(list);
    converters.add(arrayHttpMessageConverter);

    super.configureMessageConverters(converters);
}
8
Manish Patel

Je pense que cela devrait fonctionner:

@RequestMapping(value = "/Image/{id:.+}", method = RequestMethod.GET)
public ResponseEntity<byte[]> getImage(@PathVariable("id") String id) {
    byte[] image = imageService.getImage(id);
    return ResponseEntity.ok().contentType(MediaType.IMAGE_JPEG).body(image);
}

Notez que le type de contenu est défini pour ResponseEntity, pas pour HttpServletResponse directement.

16
Roman

Au cas où vous ne connaissez pas le type de fichier/mime, vous pouvez le faire .... J'ai fait cela où je prends un fichier téléchargé et remplace le nom du fichier par un guide et aucune extension et les navigateurs/téléphones intelligents sont capables charger l'image sans problèmes. la seconde consiste à servir un fichier à télécharger.

@RestController
@RequestMapping("img")
public class ImageController {

@GetMapping("showme")
public ResponseEntity<byte[]> getImage() throws IOException{
    File img = new File("src/main/resources/static/test.jpg");
    return ResponseEntity.ok().contentType(MediaType.valueOf(FileTypeMap.getDefaultFileTypeMap().getContentType(img))).body(Files.readAllBytes(img.toPath()));
}
@GetMapping("thing")
public ResponseEntity<byte[]> what() throws IOException{
    File file = new File("src/main/resources/static/thing.pdf");
    return ResponseEntity.ok()
            .header("Content-Disposition", "attachment; filename=" +file.getName())
            .contentType(MediaType.valueOf(FileTypeMap.getDefaultFileTypeMap().getContentType(file)))
            .body(Files.readAllBytes(file.toPath()));
}


}   

[~ # ~] mettre à jour [~ # ~] dans Java 9+ vous devez ajouter compile 'com.Sun.activation:javax.activation:1.2.0' dans vos dépendances, cela a également été déplacé ou récupéré par jakarta . voir cet article

7
mavriksc

En utilisant Apache Commons, vous pouvez le faire et exposer l'image sur un point de terminaison

@RequestMapping(value = "/image/{imageid}",method= RequestMethod.GET,produces = MediaType.IMAGE_JPEG_VALUE)
public @ResponseBody byte[] getImageWithMediaType(@PathVariable int imageid) throws IOException {
    InputStream in = new ByteArrayInputStream(getImage(imageid));
    return IOUtils.toByteArray(in);
    }

Toutes les images seront servies au point final /image/{imageid}

0
devyJava