引言
在构建RESTful API时,客户端和服务器之间可能需要交换多种类型的数据。Spring Web MVC通过内容协商机制(Content Negotiation)来处理不同媒体类型的请求和响应。本文将详细解析Spring Web MVC中的内容协商机制,并提供实例代码。
内容协商策略接口(ContentNegotiationStrategy)
内容协商策略接口是Spring Web MVC中用于解决请求媒体类型的核心接口。该接口定义了一个方法resolveMediaTypes()
,用于返回当前HTTP请求的媒体类型列表。
默认内容协商策略(Default ContentNegotiationStrategies)
Spring Web MVC默认注册了一些内容协商策略。以下是一个简单的控制器,用于打印默认注册的内容协商策略:
@Controller
public class MyController {
@Autowired
ApplicationContext context;
@RequestMapping("/")
@ResponseBody
public String handleRequest() {
Map<String, ContentNegotiationStrategy> map =
BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, ContentNegotiationStrategy.class,
true, false);
map.forEach((k, v) -> System.out.printf("%s=%s%n",
k, v.getClass().getSimpleName()));
return "response";
}
}
运行上述代码,访问http://localhost:8080/
,服务器控制台将打印出默认的内容协商策略。
内容协商管理器(ContentNegotiationManager)
ContentNegotiationManager
是确定请求所需媒体类型的中心类。它的resolveMediaTypes()
方法并不直接解析媒体类型,而是委托给一系列配置的内容协商策略。
内容协商策略的顺序
内容协商策略按照特定的顺序应用。如果添加了更多的策略,它们的应用顺序将按照配置指定。
媒体类型匹配标准
ContentNegotiationManager
如何应用底层策略呢?如果一个策略返回空结果或匹配所有媒体类型(即MediaType.ALL
),则尝试下一个策略,直到找到更具体的媒体类型匹配。如果没有匹配,则返回空列表,调用者将其视为MediaType.ALL
。
匹配的媒体类型如何使用
ContentNegotiationManager
的默认实例在配置时被注册为一个bean。以下是Spring MVC组件使用这个默认实例的方式:
RequestMappingHandlerMapping
RequestMappingHandlerMapping
使用ContentNegotiationManager#resolveMediaTypes()
匹配RequestMapping#produces
或RequestMapping#headers
中指定的值,直到选择一个匹配。
RequestMappingHandlerAdapter
处理器返回对象到HTTP响应体的解析
RequestMappingHandlerAdapter
使用ContentNegotiationManager#resolveMediaTypes()
返回的媒体类型来选择一个合适的HttpMessageConverter
。然后调用选定的HttpMessageConverter
的writeInternal()
方法,将处理器方法的返回值进行转换。
HTTP请求体到处理器方法参数的解析
基于请求的Content-Type
头,选择一个合适的HttpMessageConverter
,然后调用选定的HttpMessageConverter
的readInternal()
方法,将请求体转换为Java对象。
ResourceHandlerRegistry
它将内容协商策略应用于静态资源,包括图片、CSS文件等。
ViewResolverRegistry
它实际上将内容协商策略应用于ContentNegotiatingViewResolver
,后者使用内容协商策略返回的媒体类型,在视图渲染时选择一个合适的视图。
ExceptionHandlerExceptionResolver
类似于RequestMappingHandlerAdapter
,ExceptionHandlerExceptionResolver
使用内容协商策略选择一个合适的HttpMessageConverter
来准备响应(来自注解了@ExceptionHandler
的方法)。
结语
在接下来的教程中,我们将探索如何自定义默认的内容协商策略,并提供一个编写自定义内容协商策略的示例。
示例项目
使用的依赖和技术:
- spring-webmvc 4.3.9.RELEASE:Spring Web MVC。
- javax.servlet-api 3.0.1:Java Servlet API。
- junit 4.12:JUnit是一个Java的单元测试框架,由Erich Gamma和Kent Beck创建。
- JDK 1.8
- Maven 3.3.9