Spring MVC: Comment retourner une image dans @ResponseBody?

Je reçois des données d’image (comme byte[] ) de la firebase database. Comment retourner cette image dans @ResponseBody ?

MODIFIER

Je l’ai fait sans @ResponseBody utilisant HttpServletResponse comme paramètre de méthode:

 @RequestMapping("/photo1") public void photo(HttpServletResponse response) throws IOException { response.setContentType("image/jpeg"); InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg"); IOUtils.copy(in, response.getOutputStream()); } 

Utiliser @ResponseBody avec le convertisseur enregistré org.springframework.http.converter.ByteArrayHttpMessageConverter comme indiqué par @Sid ne fonctionne pas pour moi :(.

 @ResponseBody @RequestMapping("/photo2") public byte[] testphoto() throws IOException { InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg"); return IOUtils.toByteArray(in); } 

Si vous utilisez la version Spring 3.1 ou ultérieure, vous pouvez spécifier ” @RequestMapping ” dans l’annotation @RequestMapping . L’exemple ci-dessous fonctionne pour moi hors de la boîte. Pas besoin de convertisseur de registre ou quoi que ce soit si vous avez activé le mvc Web ( @EnableWebMvc ).

 @ResponseBody @RequestMapping(value = "/photo2", method = RequestMethod.GET, produces = MediaType.IMAGE_JPEG_VALUE) public byte[] testphoto() throws IOException { InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg"); return IOUtils.toByteArray(in); } 

Avec Spring 4.1 et supérieur, vous pouvez retourner à peu près n’importe quoi (comme des images, des fichiers PDF, des documents, des pots, des zips, etc.) sans aucune dépendance supplémentaire. Par exemple, ce qui suit pourrait être une méthode permettant de renvoyer une image de profil d’utilisateur à partir de MongoDB GridFS:

 @RequestMapping(value = "user/avatar/{userId}", method = RequestMethod.GET) @ResponseBody public ResponseEntity downloadUserAvatarImage(@PathVariable Long userId) { GridFSDBFile gridFsFile = fileService.findUserAccountAvatarById(userId); return ResponseEntity.ok() .contentLength(gridFsFile.getLength()) .contentType(MediaType.parseMediaType(gridFsFile.getContentType())) .body(new InputStreamResource(gridFsFile.getInputStream())); } 

Les choses à noter:

  • ResponseEntity avec InputStreamResource comme type de retour

  • Création d’un style de générateur ResponseEntity

Avec cette méthode, vous n’avez pas à vous soucier de la création automatique dans HttpServletResponse, de lancer une exception IOException ou de copier des données de stream.

En plus d’enregistrer un ByteArrayHttpMessageConverter , vous souhaiterez peut-être utiliser ResponseEntity au lieu de @ResponseBody . Le code suivant fonctionne pour moi:

 @RequestMapping("/photo2") public ResponseEntity testphoto() throws IOException { InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg"); final HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.IMAGE_PNG); return new ResponseEntity(IOUtils.toByteArray(in), headers, HttpStatus.CREATED); } 

En utilisant Spring 3.1.x et 3.2.x, voici comment procéder:

La méthode du contrôleur:

 @RequestMapping("/photo2") public @ResponseBody byte[] testphoto() throws IOException { InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg"); return IOUtils.toByteArray(in); } 

Et l’annotation mvc dans le fichier servlet-context.xml:

      image/jpeg image/png      

En plus de quelques réponses, voici quelques conseils (spring 4.1).

Si vous ne possédez pas de convertisseurs de messages configurés dans votre WebMvcConfig, le fait de disposer de ResponseEntity dans votre @ResponseBody fonctionne bien.

Si vous le faites, c’est-à-dire que vous avez configuré MappingJackson2HttpMessageConverter (comme moi) à l’aide de ResponseEntity obtenez une org.springframework.http.converter.HttpMessageNotWritableException .

La seule solution efficace dans ce cas est d’emballer un byte[] dans @ResponseBody comme suit:

 @RequestMapping(value = "/get/image/{id}", method=RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE) public @ResponseBody byte[] showImageOnId(@PathVariable("id") Ssortingng id) { byte[] b = whatEverMethodUsedToObtainBytes(id); return b; } 

Dans ce cas, rappelez-vous de configurer les messageconverters correctement (et ajoutez un ByteArrayHttpMessageConverer ) dans votre WebMvcConfig, comme ceci:

 @Override public void configureMessageConverters(List> converters) { converters.add(mappingJackson2HttpMessageConverter()); converters.add(byteArrayHttpMessageConverter()); } @Bean public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); converter.setObjectMapper(objectMapper); return converter; } @Bean public ByteArrayHttpMessageConverter byteArrayHttpMessageConverter() { ByteArrayHttpMessageConverter arrayHttpMessageConverter = new ByteArrayHttpMessageConverter(); arrayHttpMessageConverter.setSupportedMediaTypes(getSupportedMediaTypes()); return arrayHttpMessageConverter; } private List getSupportedMediaTypes() { List list = new ArrayList(); list.add(MediaType.IMAGE_JPEG); list.add(MediaType.IMAGE_PNG); list.add(MediaType.APPLICATION_OCTET_STREAM); return list; } 

Dans votre contexte d’application, déclarez un AnnotationMethodHandlerAdapter et registerByteArrayHttpMessageConverter:

        

Dans la méthode du gestionnaire, définissez également le type de contenu approprié pour votre réponse.

  @RequestMapping(value = "/get-image",method = RequestMethod.GET) public ResponseEntity getImage() throws IOException { RandomAccessFile f = new RandomAccessFile("/home/vivex/apache-tomcat-7.0.59/tmpFiles/1.jpg", "r"); byte[] b = new byte[(int)f.length()]; f.readFully(b); final HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.IMAGE_PNG); return new ResponseEntity(b, headers, HttpStatus.CREATED); } 

Travaillé pour moi

Je préfère celui-ci:

 private ResourceLoader resourceLoader = new DefaultResourceLoader(); @ResponseBody @RequestMapping(value = "/{id}", produces = "image/bmp") public Resource texture(@PathVariable("id") Ssortingng id) { return resourceLoader.getResource("classpath:images/" + id + ".bmp"); } 

Remplacez le type de support par le format d’image que vous avez.

Ça marche pour moi au spring 4.

 @RequestMapping(value = "/image/{id}", method = RequestMethod.GET) public void findImage(@PathVariable("id") Ssortingng id, HttpServletResponse resp){ final Foto anafoto =  resp.reset(); resp.setContentType(MediaType.IMAGE_JPEG_VALUE); resp.setContentLength(anafoto.getImage().length); final BufferedInputStream in = new BufferedInputStream(new ByteArrayInputStream(anafoto.getImageInBytes())); try { FileCopyUtils.copy(in, resp.getOutputStream()); resp.flushBuffer(); } catch (final IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } 

Pas des réponses a fonctionné pour moi, donc j’ai réussi à le faire comme ça:

 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.parseMediaType("your content type here")); headers.set("Content-Disposition", "attachment; filename=fileName.jpg"); headers.setContentLength(fileContent.length); return new ResponseEntity<>(fileContent, headers, HttpStatus.OK); 

Définition de l’en Content-Disposition tête Content-Disposition J’ai pu télécharger le fichier avec l’annotation @ResponseBody sur ma méthode.

Voici comment je le fais avec Spring Boot et Guava:

 @RequestMapping(value = "/getimage", method = RequestMethod.GET, produces = MediaType.IMAGE_JPEG_VALUE) public void getImage( HttpServletResponse response ) throws IOException { ByteStreams.copy( getClass().getResourceAsStream( "/preview-image.jpg" ), response.getOutputStream() ); } 

Au spring 4, il est très facile de ne pas modifier les fèves. Marquer votre type de retour uniquement sur @ResponseBody.

Exemple:-

 @RequestMapping(value = "/image/{id}") public @ResponseBody byte[] showImage(@PathVariable Integer id) { byte[] b; /* Do your logic and return */ return b; } 

Je pense que vous avez peut-être besoin d’un service pour stocker le téléchargement de fichiers et obtenir ce fichier. Vérifiez plus de détails d’ ici

1) Créer un système de stockage

 @Service public class StorageService { Logger log = LoggerFactory.getLogger(this.getClass().getName()); private final Path rootLocation = Paths.get("upload-dir"); public void store(MultipartFile file) { try { Files.copy(file.getInputStream(), this.rootLocation.resolve(file.getOriginalFilename())); } catch (Exception e) { throw new RuntimeException("FAIL!"); } } public Resource loadFile(Ssortingng filename) { try { Path file = rootLocation.resolve(filename); Resource resource = new UrlResource(file.toUri()); if (resource.exists() || resource.isReadable()) { return resource; } else { throw new RuntimeException("FAIL!"); } } catch (MalformedURLException e) { throw new RuntimeException("FAIL!"); } } public void deleteAll() { FileSystemUtils.deleteRecursively(rootLocation.toFile()); } public void init() { try { Files.createDirectory(rootLocation); } catch (IOException e) { throw new RuntimeException("Could not initialize storage!"); } } } 

2) Create Rest Controller pour télécharger et obtenir un fichier

 @Controller public class UploadController { @Autowired StorageService storageService; List files = new ArrayList(); @PostMapping("/post") public ResponseEntity handleFileUpload(@RequestParam("file") MultipartFile file) { Ssortingng message = ""; try { storageService.store(file); files.add(file.getOriginalFilename()); message = "You successfully uploaded " + file.getOriginalFilename() + "!"; return ResponseEntity.status(HttpStatus.OK).body(message); } catch (Exception e) { message = "FAIL to upload " + file.getOriginalFilename() + "!"; return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(message); } } @GetMapping("/getallfiles") public ResponseEntity> getListFiles(Model model) { List fileNames = files .stream().map(fileName -> MvcUriComponentsBuilder .fromMethodName(UploadController.class, "getFile", fileName).build().toSsortingng()) .collect(Collectors.toList()); return ResponseEntity.ok().body(fileNames); } @GetMapping("/files/{filename:.+}") @ResponseBody public ResponseEntity getFile(@PathVariable Ssortingng filename) { Resource file = storageService.loadFile(filename); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"") .body(file); } 

}

Vous devez spécifier le type de média dans la réponse. J’utilise une annotation @GetMapping avec products = MediaType.IMAGE_JPEG_VALUE. @RequestMapping fonctionnera de la même manière.

 @GetMapping(value="/current/chart",produces = MediaType.IMAGE_JPEG_VALUE) @ResponseBody public byte[] getChart() { return ...; } 

Sans un type de média, il est difficile de deviner ce qui est effectivement retourné (y compris quiconque lit le code, le navigateur et bien sûr Spring lui-même). Un octet [] n’est pas spécifique. Le seul moyen de déterminer le type de support à partir d’un octet [] consiste à détecter et à contourner les erreurs.

Fournir un type de média est juste la meilleure pratique