1. 概述
本文将演示如何使用Spring MVC框架返回图像及其他多媒体资源。我们将探讨多种实现方式,从直接操作HttpServletResponse
开始,逐步过渡到利用消息转换、内容协商和Spring的Resource
抽象的高级方案。每种方案都将深入分析其优缺点。
2. 直接操作HttpServletResponse
最基础的图像下载方式是直接操作response
对象,模拟原生Servlet实现。代码示例如下:
@RequestMapping(value = "/image-manual-response", method = RequestMethod.GET)
public void getImageAsByteArray(HttpServletResponse response) throws IOException {
InputStream in = servletContext.getResourceAsStream("/WEB-INF/images/image-example.jpg");
response.setContentType(MediaType.IMAGE_JPEG_VALUE);
IOUtils.copy(in, response.getOutputStream());
}
浏览器访问以下URL即可显示图像:
http://localhost:8080/spring-mvc-xml/image-manual-response.jpg
优点:实现简单直接,依赖org.apache.commons.io
的IOUtils
工具类。
缺点:扩展性差,MIME类型硬编码,修改图像存储位置或转换逻辑需改动代码。更灵活的方案见下节。
3. 使用HttpMessageConverter
前述方案未利用Spring MVC的消息转换和内容协商特性。启用这些特性需:
- 在控制器方法添加
@ResponseBody
注解 - 根据返回类型注册合适的消息转换器(如处理
byte[]
的ByteArrayHttpMessageConverter
)
3.1. 配置转换器
以内置的ByteArrayHttpMessageConverter
为例(默认已注册,但可显式配置):
XML配置:
<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>
Java配置:
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(byteArrayHttpMessageConverter());
}
@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;
}
3.2. 实现方法
控制器方法返回byte[]
并添加@ResponseBody
注解:
@RequestMapping(value = "/image-byte-array", method = RequestMethod.GET)
public @ResponseBody byte[] getImageAsByteArray() throws IOException {
InputStream in = servletContext.getResourceAsStream("/WEB-INF/images/image-example.jpg");
return IOUtils.toByteArray(in);
}
测试URL:
http://localhost:8080/spring-mvc-xml/image-byte-array.jpg
优点:
- 方法与
HttpServletResponse
解耦 - 转换过程高度可配置
- 响应类型通过URL后缀(如
.jpg
)自动协商,无需硬编码
缺点:
- 需手动实现数据源(本地文件/外部存储)读取逻辑
- 无法控制响应头和状态码
4. 使用ResponseEntity
类
通过ResponseEntity<byte[]>
可同时控制响应体、头部和状态码:
@RequestMapping(value = "/image-response-entity", method = RequestMethod.GET)
public ResponseEntity<byte[]> getImageAsResponseEntity() {
HttpHeaders headers = new HttpHeaders();
InputStream in = servletContext.getResourceAsStream("/WEB-INF/images/image-example.jpg");
byte[] media = IOUtils.toByteArray(in);
headers.setCacheControl(CacheControl.noCache().getHeaderValue());
ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(media, headers, HttpStatus.OK);
return responseEntity;
}
核心优势:
- 精确控制状态码:异常场景(如文件未找到)可直接返回
404
:catch (FileNotFoundException e) { return new ResponseEntity<>(null, headers, HttpStatus.NOT_FOUND); }
- 简化头部设置:比操作
HttpServletResponse
更直观,方法签名更清晰
5. 使用Resource
类返回图像
将图像抽象为Resource
对象,利用Spring的统一资源访问机制:
5.1. 实现方案
基础版本:
@ResponseBody
@RequestMapping(value = "/image-resource", method = RequestMethod.GET)
public Resource getImageAsResource() {
return new ServletContextResource(servletContext, "/WEB-INF/images/image-example.jpg");
}
增强版本(控制头部):
@RequestMapping(value = "/image-resource", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<Resource> getImageAsResource() {
HttpHeaders headers = new HttpHeaders();
Resource resource =
new ServletContextResource(servletContext, "/WEB-INF/images/image-example.jpg");
return new ResponseEntity<>(resource, headers, HttpStatus.OK);
}
核心优势:
- 解耦资源位置:通过
ResourceLoader
动态加载资源(本地文件/远程文件/类路径) - 配置化管理:图像存储路径可外部化配置,无需修改代码
- 消除样板代码:无需手动实现文件读取逻辑
6. 总结
本文对比了四种图像返回方案:
- **直接操作
HttpServletResponse
**:简单但僵硬,适合快速原型 - **
HttpMessageConverter
**:利用消息转换和内容协商,提升灵活性 - **
ResponseEntity
**:精细控制响应状态和头部,适合复杂场景 Resource
抽象:最高灵活性,统一资源访问,推荐生产环境使用
提示:Spring Boot用户可参考《使用Spring下载图像或文件》获取更现代的实现方案。完整示例代码见GitHub仓库。