mvc spring-mvc

spring-mvc - mvc - spring rest return outputstream



Spring MVC: ¿Cómo devolver la imagen en @ResponseBody? (13)

Obtengo datos de imagen (como byte[] ) de DB. ¿Cómo devolver esta imagen en @ResponseBody ?

EDITAR

Lo hice sin @ResponseBody usando HttpServletResponse como parámetro de método:

@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()); }

Usar @ResponseBody con el convertidor org.springframework.http.converter.ByteArrayHttpMessageConverter registrado como @Sid dicho no funciona para mí :(.

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


Además de registrar un ByteArrayHttpMessageConverter , es posible que desee utilizar un ResponseEntity lugar de @ResponseBody . El siguiente código funciona para mí:

@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); }


Además de un par de respuestas aquí algunos consejos (Primavera 4.1).

En caso de que no tenga ningún convertidor de mensajes configurado en su WebMvcConfig, tener ResponseEntity dentro de su @ResponseBody funciona bien.

Si lo hace, es decir, tiene configurado un MappingJackson2HttpMessageConverter (como yo) utilizando ResponseEntity devuelve un org.springframework.http.converter.HttpMessageNotWritableException .

La única solución de trabajo en este caso es envolver un byte[] en el @ResponseBody siguiente manera:

@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; }

En este caso, recuerde configurar los conversores de mensajes correctamente (y agregue un ByteArrayHttpMessageConverer ) en su WebMvcConfig, así:

@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; }


Al usar Spring 3.1.xy 3.2.x, así es como debería hacerlo:

El método del controlador:

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

Y la anotación mvc en el archivo 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>


Así es como lo hago con Spring Boot y 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() ); }


Con Spring 4.1 y superior, puede devolver casi cualquier cosa (como imágenes, archivos PDF, documentos, jarras, cremalleras, etc.) simplemente sin dependencias adicionales. Por ejemplo, lo siguiente podría ser un método para devolver una imagen de perfil de usuario 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())); }

Las cosas a tener en cuenta:

  • ResponseEntity con InputStreamResource como un tipo de retorno

  • Creación de estilo de generador ResponseEntity

Con este método, no tiene que preocuparse por el autoenvío en HttpServletResponse, lanzar una excepción IOException o copiar datos de la secuencia.


Creo que tal vez necesites un servicio para almacenar la carga de archivos y obtener ese archivo. Ver más detalles de here

1) Crear un servicio de almacenamiento

@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) Crear controlador de reposo para cargar y obtener el archivo

@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); }

}


En la primavera 4 es muy fácil que no necesites hacer ningún cambio en los frijoles. Solo marque su tipo de devolución en @ResponseBody.

Ejemplo:-

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


En su contexto de aplicación, declare un AnnotationMethodHandlerAdapter y 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>

también en el método del controlador, configure el tipo de contenido apropiado para su respuesta.


Es trabajo para mí en la primavera 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(); } }


Ninguna de las respuestas funcionó para mí, así que he logrado hacerlo así:

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);

Configuración Content-Disposition encabezado Content-Disposition Pude descargar el archivo con la anotación @ResponseBody en mi método.


Prefiero este:

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"); }

Cambia el tipo de medio a cualquier formato de imagen que tengas.


si está utilizando la versión Spring de 3.1 o posterior, puede especificar "produce" en la anotación @RequestMapping . El siguiente ejemplo me funciona de manera predeterminada. No necesita convertidor de registro ni nada si tiene habilitado @EnableWebMvc 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); }


@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); }

Trabajó para mi.