首页 > 解决方案 > Spring HttpMessageConverter 如何将请求正文解析为我定义的模型

问题描述

我有点好奇spring是如何处理这个问题的,我做了一些实验。这是我的请求处理方法:

@PostMapping(value = "/testRequestBody")
public String testRequestBody(@RequestBody MyRequestBody requestBody) {
    System.out.println(requestBody);

    return "Success";
}

我尝试了三种类型的MyRequestBody.

类型 1:

public class MyRequestBody {
private int id;
private String name;
public void setId(int id) {
    this.id = id;
}
public void setName(String name) {
    this.name = name;
}
public String toString() {
    return "MyRequestBody(id="+id+",name="+name+")";
}}

类型 2:

public class MyRequestBody {
private int id;
private String name;
public MyRequestBody(int id, String name) {
    this.id = id;
    this.name = name;
}
public String toString() {
    return "MyRequestBody(id="+id+",name="+name+")";
}}

类型 3:

public class MyRequestBody {
private int id;
private String name;
public String toString() {
    return "MyRequestBody(id="+id+",name="+name+")";
}}

Type 1 和 Type 2 我都可以MyRequestBody(id=1,name=test name)在控制台中输入{"id": 1,"name": "test name"},Type 3 给我MyRequestBody(id=0,name=null)。似乎 Spring 能够根据如何为我的模型定义 setter 和构造函数来选择不同的方式来解析我的模型。我想知道Spring是如何实现的?

标签: springspring-boot

解决方案


MappingJackson2HttpMessageConverter委托给 Jackson,将 json 转换为 java 对象的工作。因此,您所看到的行为可以用杰克逊遵循的规则来解释。

以下是 Jackson 执行的操作的简化序列,它解释了您在三个MyRequestBody定义中看到的行为。

  • 类的对象是通过调用构造函数来创建的。如果构造函数接受参数,则参数的值取自 json 字符串。以下是决定应该调用哪个构造函数的规则。

    • 如果有一个用 注释的@JsonCreator构造函数,则调用该构造函数。

    • 如果没有注释的构造函数@JsonCreator

      • 如果只有一个构造函数,则调用该构造函数。这可以是参数化构造函数或默认构造函数。
      • 如果有多个构造函数,包括默认构造函数,则调用默认构造函数。
      • 在其他情况下,会引发异常。
  • 通过调用 setX() 方法设置字段值。

Java 反射用于检查构造函数/方法并调用它们。

所以,在你的情况下

  • 对于第一个 RequestBody 定义,调用默认构造函数并调用 setX() 方法。
  • 对于第二个 RequestBody 定义,调用参数化构造函数(没有默认构造函数)
  • 调用默认构造函数。

推荐阅读