web-dev-qa-db-fra.com

Spring MVC: Comment retourner une image dans @ResponseBody?

Je reçois des données d'image (en tant que byte[]) à partir de DB. Comment renvoyer cette image en @ResponseBody?

MODIFIER

Je l'ai fait sans @ResponseBody en 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 org.springframework.http.converter.ByteArrayHttpMessageConverter enregistré comme @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);
}
129
marioosh

si vous utilisez la version 3.1 ou plus récente de Spring, vous pouvez spécifier "produit" dans l'annotation @RequestMapping. L'exemple ci-dessous fonctionne pour moi en boîte. Pas besoin de convertisseur de registre ou quoi que ce soit d'autre si vous avez activé Web MVC (@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);
}
90
michal.kreuzman

Avec Spring 4.1 et les versions ultérieures, vous pouvez renvoyer à peu près n'importe quoi (images, fichiers PDF, documents, bocaux, zips, etc.) tout simplement, sans aucune dépendance supplémentaire. Par exemple, voici une méthode permettant de renvoyer la photo de profil d'un utilisateur à partir de MongoDB GridFS:

@RequestMapping(value = "user/avatar/{userId}", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<InputStreamResource> 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 en tant que type de retour

  • Création du style de générateur ResponseEntity

Avec cette méthode, vous n'avez pas à vous soucier du câblage automatique dans HttpServletResponse, du lancement d'une exception IOException ou de la copie des données de flux.

71
Jaymes Bearden

En plus d'enregistrer une ByteArrayHttpMessageConverter, vous pouvez utiliser une ResponseEntity au lieu de @ResponseBody. Le code suivant fonctionne pour moi:

@RequestMapping("/photo2")
public ResponseEntity<byte[]> testphoto() throws IOException {
    InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg");

    final HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.IMAGE_PNG);

    return new ResponseEntity<byte[]>(IOUtils.toByteArray(in), headers, HttpStatus.CREATED);
}
57
Siggen

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:

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter">
            <property name="supportedMediaTypes">
                <list>
                    <value>image/jpeg</value>
                    <value>image/png</value>
                </list>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>
16
Peymankh

En plus de quelques réponses, voici quelques indications (Printemps 4.1).

Si vous n'avez aucun messageconverters configuré dans votre WebMvcConfig, avoir ResponseEntity dans votre @ResponseBody fonctionne bien.

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

La seule solution efficace dans ce cas consiste à envelopper un byte[] dans le @ResponseBody comme suit:

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

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

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> 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<MediaType> getSupportedMediaTypes() {
    List<MediaType> list = new ArrayList<MediaType>();
    list.add(MediaType.IMAGE_JPEG);
    list.add(MediaType.IMAGE_PNG);
    list.add(MediaType.APPLICATION_OCTET_STREAM);
    return list;
}
11
s.ijpma
 @RequestMapping(value = "/get-image",method = RequestMethod.GET)
public ResponseEntity<byte[]> 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<byte[]>(b, headers, HttpStatus.CREATED);



}

Travaillé pour moi.

6
Vivek

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

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
  <property name="messageConverters">
    <util:list>
      <bean id="byteArrayMessageConverter" class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
    </util:list>
  </property>
</bean> 

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

6
Sid

Je préfère celle-ci:

private ResourceLoader resourceLoader = new DefaultResourceLoader();

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

Changez le type de support au format d'image que vous avez.

4
Tarion

C'est un travail pour moi au printemps 4.

@RequestMapping(value = "/image/{id}", method = RequestMethod.GET)
public void findImage(@PathVariable("id") String id, HttpServletResponse resp){

        final Foto anafoto = <find object>
        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();
        }

}
3
Furetto

Aucune des réponses ne fonctionnait pour moi, alors 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-tête Content-Disposition J'ai été en mesure de télécharger le fichier avec l'annotation @ResponseBody sur ma méthode.

2
Paulius Matulionis

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() );
}
1
Wim Deblauwe

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

1) Créer un service 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(String 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) Créer un contrôleur de repos pour télécharger et obtenir un fichier

@Controller
public class UploadController {

@Autowired
StorageService storageService;

List<String> files = new ArrayList<String>();

@PostMapping("/post")
public ResponseEntity<String> handleFileUpload(@RequestParam("file") MultipartFile file) {
    String 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<List<String>> getListFiles(Model model) {
    List<String> fileNames = files
            .stream().map(fileName -> MvcUriComponentsBuilder
                    .fromMethodName(UploadController.class, "getFile", fileName).build().toString())
            .collect(Collectors.toList());

    return ResponseEntity.ok().body(fileNames);
}

@GetMapping("/files/{filename:.+}")
@ResponseBody
public ResponseEntity<Resource> getFile(@PathVariable String filename) {
    Resource file = storageService.loadFile(filename);
    return ResponseEntity.ok()
            .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"")
            .body(file);
}

}

0
Long Nguyen

Au printemps 4, il est très facile de ne pas modifier les haricots Marquez uniquement votre type de retour sur @ResponseBody.

Exemple:-

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

Vous devez spécifier le type de support dans la réponse. J'utilise une annotation @GetMapping avec producteurs = 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 type de support, il est difficile de deviner ce qui est réellement renvoyé (quiconque lit le code, le navigateur et bien sûr Spring lui-même). Un octet [] n'est pas spécifique. La seule façon de déterminer le type de média à partir d'un octet [] consiste à renifler et à deviner.

La fourniture d'un type de support est juste meilleure pratique _

0
coseos