Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

Serving static files to the client can be done in a variety of ways, and using a Spring Controller isn’t necessarily the best available option.

However, sometimes the controller route is necessary – and that’s what we’re going to be focused on in this quick article.

2. Maven Dependencies

First, we’ll need to add a dependency to our pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

That’s all, we do not need anything else here. For version information, head over to Maven Central.

3. Using @ResponseBody

The first straightforward solution is to use the @ResponseBody annotation on a controller method to indicate that the object returned by the method should be marshalled directly to the HTTP response body:

@GetMapping("/get-text")
public @ResponseBody String getText() {
    return "Hello world";
}

Thus, this method will just return the string Hello world instead of returning a view whose name is Hello world, like a more typical MVC application.

With @ResponseBody we can return pretty much any media type, as long as we have a corresponding HTTP Message converter that can handle and marshall that to the output stream.

4. Using produces for Returning Images

Returning byte arrays allows us to return almost anything – such as images or files:

@GetMapping(value = "/image")
public @ResponseBody byte[] getImage() throws IOException {
    InputStream in = getClass()
      .getResourceAsStream("/com/baeldung/produceimage/image.jpg");
    return IOUtils.toByteArray(in);
}

Here, we’re not defining that the returned byte array is an image. Therefore, the client won’t be able to handle this as an image – and more than likely the browser will simply display the actual bytes of the image.

To define that the returned byte array corresponds to an image, we can set the produces attribute of the @GetMapping annotation to precise the MIME type of the returned object:

@GetMapping(
  value = "/get-image-with-media-type",
  produces = MediaType.IMAGE_JPEG_VALUE
)
public @ResponseBody byte[] getImageWithMediaType() throws IOException {
    InputStream in = getClass()
      .getResourceAsStream("/com/baeldung/produceimage/image.jpg");
    return IOUtils.toByteArray(in);
}

Here produces is set to MediaType.IMAGE_JPEG_VALUE to indicate that the returned object must be handled as a JPEG image.

And now, the browser is going to recognize and properly display the response body as an image.

5. Using produces for Returning Raw Data

The parameter produces can be set to a lot of different values (the complete list can be found here) depending on the type of object we want to return.

Therefore, if we want to return a raw file, we can simply use APPLICATION_OCTET_STREAM_VALUE:

@GetMapping(
  value = "/get-file",
  produces = MediaType.APPLICATION_OCTET_STREAM_VALUE
)
public @ResponseBody byte[] getFile() throws IOException {
    InputStream in = getClass()
      .getResourceAsStream("/com/baeldung/produceimage/data.txt");
    return IOUtils.toByteArray(in);
}

Alternatively, we can return a ByteArrayResource instead of a byte array:

@GetMapping(value = "/get-file-via-byte-array-resource", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public @ResponseBody Resource getFileViaByteArrayResource() throws IOException, URISyntaxException {
    Path path = Paths.get(getClass().getResource("/com/baeldung/produceimage/data.txt").toURI());
    ByteArrayResource resource = new ByteArrayResource(Files.readAllBytes(path));
    return resource;
}

The Resource class is a high-level abstraction provided by Spring. It allows us to write generic and flexible code that can handle resources from various sources. Using a Resource over an InputStream has the following benefits:

  • Resource provides additional metadata about the resource.
  • It’s possible to use a Resource in conjunction with other Spring abstractions.
  • It’s easier to mock.

6. Setting contentType Dynamically

We’ll now see how we can set the content type of the response dynamically. In this case, we can’t use the produces parameter because it expects a constant. We’ll need to directly set the contentType of the ResponseEntity instead:

@GetMapping("/get-image-dynamic-type")
@ResponseBody
public ResponseEntity<InputStreamResource> getImageDynamicType(@RequestParam("jpg") boolean jpg) {
    MediaType contentType = jpg ? MediaType.IMAGE_JPEG : MediaType.IMAGE_PNG;
    InputStream in = jpg ?
      getClass().getResourceAsStream("/com/baeldung/produceimage/image.jpg") :
      getClass().getResourceAsStream("/com/baeldung/produceimage/image.png");
    return ResponseEntity.ok()
      .contentType(contentType)
      .body(new InputStreamResource(in));
}

We’ve decided to set the content type of the returned image depending on a query parameter.

7. Conclusion

In this quick article, we had a look at a simple problem – returning images or files from a Spring Controller. In particular, we showcased various possible response types, such as String, byte array, and Resource.

And, as always, the example code can be found over on Github.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.