17

I am facing problem while sending an Image using Spring Web Service.

I have written controller as below

@Controller
public class WebService {

    @RequestMapping(value = "/image", headers = "Accept=image/jpeg, image/jpg, image/png, image/gif", method = RequestMethod.GET)
    public @ResponseBody byte[] getImage() {
        try {
            InputStream inputStream = this.getClass().getResourceAsStream("myimage.jpg");
            BufferedImage bufferedImage = ImageIO.read(inputStream);
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ImageIO.write( bufferedImage  , "jpg", byteArrayOutputStream);
            return byteArrayOutputStream.toByteArray();

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

@ResponseBody converts response into JSON.

I am using RestClient to test Web Service.

But When I'm hitting with http://localhost:8080/my-war-name/rest/image URL.

Header 
Accept=image/jpg

I facing following error on RestClient

Response body conversion to string using windows-1252 encoding failed. Response body not set!

When i'm using browsers Chrome and Firefox

Headers are not added so error was expected (Please guide me on this)

HTTP Status 405 - Request method 'GET' not supported

type Status report

message Request method 'GET' not supported

description The specified HTTP method is not allowed for the requested resource (Request method 'GET' not supported).

I have also faced below error once

The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers ()

I have followed http://krams915.blogspot.com/2011/02/spring-3-rest-web-service-provider-and.html tutorial.

My requirment is to send image in byte format to Android Client.

skaffman
  • 398,947
  • 96
  • 818
  • 769
Ketan
  • 314
  • 2
  • 4
  • 15
  • possible duplicate of [Spring MVC: How to return image in @ResponseBody?](http://stackoverflow.com/questions/5690228/spring-mvc-how-to-return-image-in-responsebody) – skaffman Dec 28 '11 at 12:51

6 Answers6

24

In addition to answer provided by soulcheck. Spring has added produces property to @RequestMapping annotation. Therefore solution is more easier now:

@RequestMapping(value = "/image", method = RequestMethod.GET, produces = "image/jpg")
public @ResponseBody byte[] getFile()  {
    try {
        // Retrieve image from the classpath.
        InputStream is = this.getClass().getResourceAsStream("/test.jpg"); 

        // Prepare buffered image.
        BufferedImage img = ImageIO.read(is);

        // Create a byte array output stream.
        ByteArrayOutputStream bao = new ByteArrayOutputStream();

        // Write to output stream
        ImageIO.write(img, "jpg", bao);

        return bao.toByteArray();
    } catch (IOException e) {
        logger.error(e);
        throw new RuntimeException(e);
    }
}
6

The answer by #soulcheck is partially right. The configuration won't work in the latest version of Spring as it would clash with mvc-annotation element. Try the below configuration.

<mvc:annotation-driven>
  <mvc:message-converters register-defaults="true">
    <bean class="org.springframework.http.converter.BufferedImageHttpMessageConverter"/>
  </mvc:message-converters>
</mvc:annotation-driven>

Once you have above configuration in your config file. The below code will work:

@RequestMapping(value = "/image", headers = "Accept=image/jpeg, image/jpg, image/png, image/gif", method = RequestMethod.GET)
public @ResponseBody BufferedImage getImage() {
    try {
        InputStream inputStream = this.getClass().getResourceAsStream("myimage.jpg");
        return ImageIO.read(inputStream);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}
jsf
  • 2,851
  • 9
  • 30
  • 33
4

See this article on the excellent baeldung.com website.

You can use the following code in your Spring Controller:

@RequestMapping(value = "/rest/getImgAsBytes/{id}", method = RequestMethod.GET)
public ResponseEntity<byte[]> getImgAsBytes(@PathVariable("id") final Long id, final HttpServletResponse response) {
    HttpHeaders headers = new HttpHeaders();
    headers.setCacheControl(CacheControl.noCache().getHeaderValue());
    response.setContentType(MediaType.IMAGE_JPEG_VALUE);

    try (InputStream in = imageService.getImageById(id);) { // Spring service call
        if (in != null) {
            byte[] media = IOUtils.toByteArray(in);
            ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(media, headers, HttpStatus.OK);
            return responseEntity;
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return new ResponseEntity<>(null, headers, HttpStatus.NOT_FOUND);
}

Notes: IOUtils comes from common-io apache library. I am using a Spring Service to retrieve img/pdf Blobs from a database.

Similar handling for pdf files, except that you need to use MediaType.APPLICATION_PDF_VALUE in the content type. And you can refer the image file or the pdf file from an html page:

<html>
  <head>
  </head>
  <body>
    <img src="https://localhost/rest/getImgDetectionAsBytes/img-id.jpg" />
    <br/>
    <a href="https://localhost/rest/getPdfBatchAsBytes/pdf-id.pdf">Download pdf</a>
  </body>
</html>

... or you can call the web service method directly from your browser.

razvanone
  • 1,351
  • 18
  • 27
2

Drop conversion to json and sent the byte array as-is.

The only drawback is that it sends application/octet-stream content type by default.

If that doesn't suite you you can use BufferedImageHttpMessageConverter which can send any image type supported by registered image readers.

Then you can change your method to:

@RequestMapping(value = "/image", headers = "Accept=image/jpeg, image/jpg, image/png, image/gif", method = RequestMethod.GET)
public @ResponseBody BufferedImage getImage() {
    try {
        InputStream inputStream = this.getClass().getResourceAsStream("myimage.jpg");
        return ImageIO.read(inputStream);


    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

while having :

 <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="order" value="1"/>
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.BufferedImageHttpMessageConverter"/>
        </list>
    </property>
</bean>

in your spring config.

soulcheck
  • 36,297
  • 6
  • 91
  • 90
0

If you are using spring boot, just placing the images in the right folder in your classpath will do the trick. Check https://www.baeldung.com/spring-mvc-static-resources

NobodySomewhere
  • 2,997
  • 1
  • 16
  • 12
0

Here's the method I wrote for this.

I needed to both display the image inline on a page, and optionally download it to the client, so I take an optional parameter to set the appropriate header for that.

Document is my entity model to represent documents. I have the files themselves stored on disc named after the ID of the record that stores that document. The original filename and mime type are stored in the Document object.

@RequestMapping("/document/{docId}")
public void downloadFile(@PathVariable Integer docId, @RequestParam(value="inline", required=false) Boolean inline, HttpServletResponse resp) throws IOException {

    Document doc = Document.findDocument(docId);

    File outputFile = new File(Constants.UPLOAD_DIR + "/" + docId);

    resp.reset();
    if (inline == null) {
        resp.setHeader("Content-Disposition", "attachment; filename=\"" + doc.getFilename() + "\"");
    }
    resp.setContentType(doc.getContentType());
    resp.setContentLength((int)outputFile.length());

    BufferedInputStream in = new BufferedInputStream(new FileInputStream(outputFile));

    FileCopyUtils.copy(in, resp.getOutputStream());
    resp.flushBuffer();

}
Dan Ray
  • 21,623
  • 6
  • 63
  • 87