Spring MVC: How to return image in @ResponseBody?
我正在从DB获取图像数据(如
编辑
我没有使用
1 2 3 4 5 6 | @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()); } |
将
1 2 3 4 5 6 | @ResponseBody @RequestMapping("/photo2") public byte[] testphoto() throws IOException { InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg"); return IOUtils.toByteArray(in); } |
如果您使用的是Spring 3.1或更高版本,则可以在
1 2 3 4 5 6 | @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); } |
在Spring 4.1及更高版本中,您可以非常简单地返回几乎所有内容(例如图片,pdf,文档,jar,zip等),而无需任何额外的依赖关系。例如,以下可能是从MongoDB GridFS返回用户的个人资料图片的方法:
1 2 3 4 5 6 7 8 9 10 | @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())); } |
注意事项:
-
以InputStreamResource作为返回类型的ResponseEntity
-
ResponseEntity构建器样式创建
使用此方法,您不必担心HttpServletResponse中的自动装配,抛出IOException或复制流数据。
除了注册
1 2 3 4 5 6 7 8 9 | @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); } |
通过使用Spring 3.1.x和3.2.x,这是您应该这样做的方式:
控制器方法:
1 2 3 4 5 | @RequestMapping("/photo2") public @ResponseBody byte[] testphoto() throws IOException { InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg"); return IOUtils.toByteArray(in); } |
并在servlet-context.xml文件中添加了mvc批注:
1 2 3 4 5 6 7 8 9 10 11 12 | <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> |
除了几个答案,这里还有一些指针(Spring 4.1)。
如果您在WebMvcConfig中没有配置任何消息转换器,则在
如果这样做,即您使用
在这种情况下,唯一可行的解??决方案是将
1 2 3 4 5 | @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; } |
在这种情况下,请记住在WebMvcConfig中正确配置消息转换器(并添加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | @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; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @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); } |
为我工作。
在您的应用程序上下文中,声明AnnotationMethodHandlerAdapter和registerByteArrayHttpMessageConverter:
1 2 3 4 5 6 7 | <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> |
还可以在处理程序方法中为您的响应设置适当的内容类型。
我更喜欢这个:
1 2 3 4 5 6 7 | 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"); } |
将媒体类型更改为您拥有的图像格式。
我在春季4上班。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | @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(); } } |
没有答案对我有用,所以我设法做到了:
1 2 3 4 5 | 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); |
设置
您应该在响应中指定媒体类型。我正在将@GetMapping注释与Produces = MediaType.IMAGE_JPEG_VALUE一起使用。 @RequestMapping将起作用。
1 2 3 4 5 | @GetMapping(value="/current/chart",produces = MediaType.IMAGE_JPEG_VALUE) @ResponseBody public byte[] getChart() { return ...; } |
没有媒体类型,很难猜测实际返回的内容(包括任何阅读代码的人,浏览器,当然还有Spring本身)。 byte []只是不具体。从byte []确定媒体类型的唯一方法是嗅探和猜测。
提供媒体类型只是最佳实践
这就是我使用Spring Boot和Guava的方法:
1 2 3 4 5 | @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)创建一个存储服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | @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)创建Rest Controller以上传并获取文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | @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); } |
}
在春季4中,您很容易不需要在bean中进行任何更改。仅将返回类型标记为@ResponseBody。
例:-
1 2 3 4 5 6 7 8 | @RequestMapping(value ="/image/{id}") public @ResponseBody byte[] showImage(@PathVariable Integer id) { byte[] b; /* Do your logic and return */ return b; } |