@RequestBody 注释究竟是如何工作的以及它与 HttpMessageConverter 接口有何关系?

How exactly works @RequestBody annotation and how it is related to the HttpMessageConverter interface?

我正在研究 Spring 如何处理 REST Web 服务,我对 HttpMessageConverter 的概念有一些疑问.

在官方文档上我可以看到:

Strategy interface that specifies a converter that can convert from and to HTTP requests and responses.

所以 HttpMessageConverter 似乎是一个接口,但 策略接口 究竟是什么?是否与策略模式有关?

所以据我了解Spring在使用@EnableWebMvc[=时自动提供一些默认注册的实现14=]

但是这些实现到底是什么?你能给我一个实际的例子吗?

我认为它是这样工作的:

例如,客户端执行一个 HttpRequest 并在此请求的正文中放入一条 JSON 消息(我不是很实际,但我认为我可以做一些事情像这样),然后处理此 HttpRequst 的控制器使用 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 转换器。为什么在前面的例子中没有指定?如何选择合适的转换器?

Tnx

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

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

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

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

@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 请求