1. 概述

向客户端提供静态文件有多种实现方式,Spring Controller并非总是最佳选择。但在某些场景下,通过Controller处理是必要的——这正是本文要探讨的核心内容。

2. Maven依赖

首先在pom.xml中添加核心依赖:

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

仅此而已,无需其他依赖。版本信息可查阅Maven Central

3. 使用@ResponseBody

最直接的方案是在Controller方法上使用@ResponseBody注解,表明返回对象应直接序列化到HTTP响应体:

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

此方法直接返回字符串"Hello world",而非像传统MVC应用那样返回视图名。

借助@ResponseBody,我们可以返回任何媒体类型,前提是存在对应的HTTP消息转换器能处理该类型并写入输出流。

4. 使用produces返回图片

通过返回字节数组,我们可以处理图片或文件等二进制内容:

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

⚠️ 这里未声明返回的是图片,导致客户端无法正确处理——浏览器很可能直接显示原始字节流。

要明确声明返回类型为图片,需在@GetMapping中设置produces属性指定MIME类型:

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

通过设置produces = MediaType.IMAGE_JPEG_VALUE,浏览器将正确识别并渲染JPEG图片。

5. 使用produces返回原始文件

produces参数支持多种值(完整列表见官方文档),根据返回对象类型灵活配置。

返回原始文件时,可直接使用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);
}

替代方案:使用ByteArrayResource替代字节数组

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

Resource是Spring提供的高级抽象,优势包括:

  • 提供资源元数据
  • 可与其他Spring抽象无缝集成
  • 更易于单元测试

6. 动态设置contentType

当需要动态设置响应类型时(如根据参数返回不同格式图片),produces参数无法满足需求(要求常量值)。此时应直接操作ResponseEntity

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

根据查询参数jpg动态决定返回JPEG或PNG图片,并设置对应的contentType

7. 总结

本文探讨了Spring Controller返回图片/文件的几种实现方式:

  • 使用@ResponseBody处理基础类型
  • 通过produces声明媒体类型
  • 利用Resource抽象处理文件
  • 动态设置ResponseEntitycontentType

完整示例代码可在GitHub获取。


原始标题:Returning an Image or a File with Spring