@RequestBody注解的工作原理是什么?它与HttpMessageConverter接口有什么关系?

12

我正在学习Spring如何处理REST web服务,并且我对HttpMessageConverter的概念有一些疑问。

在官方文档中,我可以看到:

策略接口,指定一个转换器,可以将HTTP请求和响应进行转换。

因此,HttpMessageConverter似乎是一个接口,但是什么是策略接口?与策略模式相关还是不相关?

所以,从我的理解来看,当使用@EnableWebMvc时,Spring会自动提供一些默认注册的实现。

但是,这些实现到底是做什么的?能否提供一个实际的例子?

我认为它的工作方式如下:

例如,客户端执行一个HttpRequest,在该请求的主体中放置一个JSON消息(我不太熟练,但我认为我可以做类似于这样的事情),然后处理这个HttpRequest的控制器使用HttpMessageConverter的实现将此JSON消息转换为模型对象。我认为反之亦然。

我的思路正确吗?还是我漏了什么?

另一个疑问与@RequestBody注解有关(我认为它与前面的主题有关)。

我有这个例子:

@RequestMapping(value="/orders/{id}", method=RequestMethod.PUT)
@ResponseStatus(HttpStatus.NO_CONTENT) // 204
public void updateOrder(@RequestBody Order updatedOrder, @PathVariable("id") long id) {
    // process updated order data and return empty response
    orderManager.updateOrder(id, updatedOrder);
}
因此,我认为@RequestBody Order updatedOrder会从HttpRequest的body中获取updatedOrder输入参数的值,然后使用HttpMessageConverter的实现将其转换为一个Order对象。
这是正确的吗?如果正确,如何选择正确的转换器?
例如,在这里我找到了另一个类似于之前的示例:http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html
@Controller
@RequestMapping(value = "/pets", method = RequestMethod.POST, consumes="application/json")
public void addPet(@RequestBody Pet pet, Model model) {
    // implementation omitted
}

我认为这里明确指定必须使用JSON转换成MODEL OBJECT。为什么在先前的例子中没有说明呢?如何选择正确的转换器?

谢谢

1个回答

20

Spring的HandlerMethodArgumentResolver生成处理程序方法参数,而Spring的HandlerMethodReturnValueHandler处理处理程序方法返回值。同时处理@ResponseBody@RequestBody的实现是RequestResponseBodyMethodProcessor

其中一个在默认情况下(@EnableWebMvc配置)注册,并带有默认的HttpMessageConverter实例列表。这在WebMvcConfigurationSupport#addDefaultHttpMessageConverters(List)中完成。您可以查找源代码并查看添加了哪些实例以及以何种顺序添加了它们。

对于@RequestBody参数的生成,当Spring循环遍历HttpMessageConverter实例时,会检查该实例是否可以HttpMessageConverter#canRead请求中给定的内容类型并且可以生成参数类型的实例。如果可以,则Spring将使用该HttpMessageConverter生成一个参数。如果不能,则Spring将跳过它并尝试下一个实例,直到用完为止。此时,它将抛出异常。

对于@ResponseBody,流程相同,只是Spring现在使用HttpMessageConverter#canWrite。它将检查HttpMessageConverter是否可以序列化返回类型并生成符合预期响应中的内容类型的响应内容(在Accept请求头中给出)。

@RequestParamconsumes属性

@RequestMapping(value = "/pets", method = RequestMethod.POST, consumes="application/json")

与上述策略无关。在此,consumes 的唯一作用是限制处理程序的映射。例如,考虑这两个处理程序:

@RequestMapping(value = "/pets", method = RequestMethod.POST)

@RequestMapping(value = "/pets", method = RequestMethod.POST, consumes="application/json")

第一个处理任何内容类型的/pets请求。第二个只能处理那些内容类型为application/json/pets请求。


那么它是如何将特定的HTTP输入字段映射到该对象的特定变量中的呢?例如,将HTML中的名称和电子邮件映射到类的名称和电子邮件特征。 - Shivam Papat
1
@ShivamPapat 这完全取决于内容类型和用于解析它的 HttpMessageConverter 实现。对于 JSON,它可能使用依赖于 Jackson 库的实现(以及它的工作方式)。 - Sotirios Delimanolis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接