@RestController is not meant to be used to return views to be resolved. It is supposed to return data which will be written to the body of the response, hence the inclusion of @ResponseBody .
You can access the static resources by just appending the path of them inside the static/public folder to your base URL. Example: You have an image in the folder src/main/resources/static/images/brand. png , the URL for that would be ${host}/images/brand.
ResponseEntity represents an HTTP response, including headers, body, and status. While @ResponseBody puts the return value into the body of the response, ResponseEntity also allows us to add headers and status code.
if you are using Spring version of 3.1 or newer you can specify "produces" in @RequestMapping
annotation. Example below works for me out of box. No need of register converter or anything else if you have web mvc enabled (@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);
}
With Spring 4.1 and above, you can return pretty much anything (such as pictures, pdfs, documents, jars, zips, etc) quite simply without any extra dependencies. For example, the following could be a method to return a user's profile picture from 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()));
}
The things to note:
ResponseEntity with InputStreamResource as a return type
ResponseEntity builder style creation
With this method you dont have to worry about autowiring in the HttpServletResponse, throwing an IOException or copying stream data around.
In addition to registering a ByteArrayHttpMessageConverter
, you may want to use a ResponseEntity
instead of @ResponseBody
. The following code works for me :
@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);
}
By using Spring 3.1.x and 3.2.x, this is how you should do it:
The controller method:
@RequestMapping("/photo2")
public @ResponseBody byte[] testphoto() throws IOException {
InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg");
return IOUtils.toByteArray(in);
}
And the mvc annotation in servlet-context.xml file:
<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>
In addition to a couple of answers here a few pointers (Spring 4.1).
Incase you don't have any messageconverters configured in your WebMvcConfig, having ResponseEntity
inside your @ResponseBody
works well.
If you do, i.e. you have a MappingJackson2HttpMessageConverter
configured (like me) using the ResponseEntity
returns a org.springframework.http.converter.HttpMessageNotWritableException
.
The only working solution in this case is to wrap a byte[]
in the @ResponseBody
as follows:
@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;
}
In this case do rememeber to configure the messageconverters properly (and add a ByteArrayHttpMessageConverer
) in your WebMvcConfig, like so:
@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;
}
I prefere this one:
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");
}
Change the media type to what ever image format you have.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With