Reputation: 28596
I'm getting image data (as byte[]
) from DB. How to return this image in @ResponseBody
?
EDIT
I did it without @ResponseBody
using HttpServletResponse
as method parameter:
@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());
}
Using @ResponseBody
with registered org.springframework.http.converter.ByteArrayHttpMessageConverter
converter as @Sid said doesn't work for me :(.
@ResponseBody
@RequestMapping("/photo2")
public byte[] testphoto() throws IOException {
InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg");
return IOUtils.toByteArray(in);
}
Upvotes: 156
Views: 217468
Reputation: 1
When using produces with MediaType.IMAGE_JPEG_VALUE, make sure that you are returning byte[], but not Byte[]. Very strange, but spring cannot convert it and raises an exception: no converter found.
Upvotes: 0
Reputation: 144
You should specify the media type in the response. I'm using a @GetMapping annotation with produces = MediaType.IMAGE_JPEG_VALUE. @RequestMapping will work the same.
@GetMapping(value="/current/chart",produces = MediaType.IMAGE_JPEG_VALUE)
@ResponseBody
public byte[] getChart() {
return ...;
}
Without a media type, it is hard to guess what is actually returned (includes anybody who reads the code, browser and of course Spring itself). A byte[] is just not specific. The only way to determine the media type from a byte[] is sniffing and guessing around.
Providing a media type is just best practice
Upvotes: 5
Reputation: 11024
I think you maybe need a service to store file upload and get that file. Check more detail from here
1) Create a Storage Sevice
@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) Create Rest Controller to upload and get file
@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);
}
}
Upvotes: 0
Reputation: 12410
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);
}
Upvotes: 103
Reputation: 17174
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.
Upvotes: 7
Reputation: 940
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;
}
Upvotes: 15
Reputation: 2515
@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);
}
Worked For Me.
Upvotes: 6
Reputation: 379
It's work for me in Spring 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();
}
}
Upvotes: 3
Reputation: 23413
Non of the answers worked for me, so I've managed to do it like that:
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);
Setting Content-Disposition
header I was able to download the file with the @ResponseBody
annotation on my method.
Upvotes: 2
Reputation: 2049
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.
Upvotes: 87
Reputation: 26878
This is how I do it with Spring Boot and 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() );
}
Upvotes: 1
Reputation: 2177
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);
}
Upvotes: 63
Reputation: 3001
In spring 4 it's very easy you don't need to make any changes in beans. Only mark your return type to @ResponseBody.
Example:-
@RequestMapping(value = "/image/{id}")
public @ResponseBody
byte[] showImage(@PathVariable Integer id) {
byte[] b;
/* Do your logic and return
*/
return b;
}
Upvotes: 0
Reputation: 2046
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>
Upvotes: 17
Reputation: 119
In your application context declare a AnnotationMethodHandlerAdapter and 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>
also in the handler method set appropriate content type for your response.
Upvotes: 6