2011-04-16 265 views
115

我從數據庫中獲取圖像數據(如byte[])。如何在@ResponseBody中返回此圖片?Spring MVC:如何在@ResponseBody中返回圖像?

編輯

我使用HttpServletResponse作爲方法的參數做到了無@ResponseBody

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

使用@ResponseBody與註冊org.springframework.http.converter.ByteArrayHttpMessageConverter轉換器@Sid說我不工作:(

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

回答

6

在您的應用程序上下文中,decl是AnnotationMethodHandlerAdapter上和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> 

也在處理方法設置適當的內容類型的響應。

+0

它不適合工作我。上面的細節。 – marioosh 2011-06-06 11:37:28

+0

它不適用於我 – jsf 2012-10-25 17:02:10

+0

@jsinghfoss請參閱最佳答案。 – Peymankh 2012-10-26 13:28:27

55

除了註冊ByteArrayHttpMessageConverter,您可能還想使用ResponseEntity而不是@ResponseBody。下面的代碼對我的作品:

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

通過使用Spring 3.1.X和3.2.x中,這是你應該怎麼做:

控制器方法:

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

而servlet-context.xml文件中的mvc註釋:

<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> 
82

如果您使用的是3.1或更新版本的Spring版本,則可以指定「prod在@RequestMapping註釋中使用「uces」。下面的例子爲我開箱即用。如果您啓用了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); 
} 
+1

感謝這個答案爲我工作。 – Simon 2015-07-19 14:47:53

0

在春季4,你很容易就可以不需要對豆做任何改變。只將您的返回類型標記爲@ResponseBody。

例子: -

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

問題我得到這是內容類型設置不正確。 – ETL 2014-12-09 04:03:26

1

這是我要做的事與Spring引導和番石榴:

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

使用Spring 4.1以上,就可以返回相當多的東西(如圖片,PDF文件,文件,罐子,拉鍊等),沒有任何額外的依賴關係。例如,下面可能是從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())); 
} 

的注意事項:

  • ResponseEntity用的InputStreamResource作爲返回類型

  • ResponseEntity生成器樣式創建

With t他不需要擔心HttpServletResponse中的自動裝配,拋出IOException或複製流數據。答案

+1

這會拋出以下異常,你如何序列化MyInputStream?:無法寫入內容:找不到類的串化器com.mongodb.gridfs.GridFSDBFile $ MyInputStream – 2015-08-22 04:14:40

+0

雖然這主要是作爲你可能做的一個例子,但Mongo-Java -Driver 3.0.3與GridFsDBFile.getInputStream()不會返回一個名爲MyInputStream的匿名類。我會檢查你的版本 - 也許更新? – 2015-08-24 17:08:54

+3

我喜歡這如何流文件,而不是複製整個內存中的東西。另見http://stackoverflow.com/questions/20333394/return-a-stream-with-spring-mvcs-responseentity – 2015-12-16 09:59:10

2

不爲我工作,所以我已經成功地做到這一點像:

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

設置Content-Disposition頭,我能夠下載該文件與@ResponseBody註釋上我的方法。

+3

我不知道你的方法簽名看起來像 – 2015-10-23 06:58:22

3

這對我的工作在春季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(); 
     } 

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



} 

爲我工作。

10

除了幾個答案這裏幾點(Spring 4.1)。

因爲您的WebMvcConfig中沒有配置任何messageconverters,因此您的@ResponseBody中的ResponseEntity工作良好。

如果你這樣做,即你有一個MappingJackson2HttpMessageConverter配置(如我)使用ResponseEntity返回org.springframework.http.converter.HttpMessageNotWritableException

唯一的工作在這種情況下,解決方法是在@ResponseBody包裝一個byte[]如下:

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

在這種情況下就rememeber配置得當了MessageConverter(並添加ByteArrayHttpMessageConverer)在WebMvcConfig,像所以:

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

我這個prefere一個:

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

將媒體類型更改爲您擁有的任何圖像格式。

+1

良好的調用' ResourceLoader',但是像在你的例子中那樣從外部輸入構建一個路徑名是一個壞主意:https://cwe.mitre.org/data/definitions/22.html – qerub 2016-11-14 22:07:01

0

我想你可能需要一個服務來存儲文件上傳並獲取該文件。 從here

1檢查更詳細)創建存儲服務隊

@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)創建休息控制器上傳和獲取文件

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

}

相關問題