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();
Où 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.
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);
}
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.
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
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}