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
抽象处理文件 - 动态设置
ResponseEntity
的contentType
完整示例代码可在GitHub获取。