在使用Spring Boot框架的Spring MVC时,通过HTTP请求传递的JSON参数无法正确映射到Java类的对应字段上。进行了一系列的排查,发现问题出在使用了Lombok的@Data注解上。示例代码如下:
@RestController
@RequestMapping("/user")
public class UserController {
/**
* 保存用户
*/
@PostMapping("/save")
public void save(@RequestBody User user) {
System.out.println(user.getName());
System.out.println(user.getCName());
}
}
// JSON参数
{
"name":"英文名",
"cName":"中文名"
}
解决这个问题的关键在于知道SpringBoot是如何将JSON请求参数映射到Java类的。在上面的示例中User是请求对象类,它具有与JSON参数对应的属性。并@RequestBody注解告诉SpringBoot将请求体中的JSON参数映射到user对象上。
当你发送一个POST请求到/user/save路径时,SpringBoot将自动解析请求体中的JSON参数,并将其映射到user对象,执行具体的业务逻辑。
在SpringBoot中,使用@RequestBody注解可以实现请求体到对象映射的原理是通过SpringMVC的消息转换器(MessageConverter)机制实现的。SpringMVC在处理请求时会根据请求头中的Content-Type判断请求体的类型,然后选择合适的消息转换器来将请求体转换为Java对象。当使用 @RequestBody 注解时,Spring MVC 会使用消息转换器将请求体的内容转换为指定的对象类型。默认情况下,Spring Boot 集成了 Jackson 库作为 JSON 消息转换器,它可以将 JSON 数据转换为 Java 对象。具体的工作流程如下:
总结:对象的属性名与 JSON 数据的键名匹配是默认的映射规则,与对象的 set 方法紧密相关。如果属性名与键名一致并且存在对应的 set 方法,转换器会使用 set 方法将值设置到对象的属性中。如果属性是私有的或者没有对应的 set 方法,可以通过注解来指定其他的映射方式。
以下是SpringBoot生成的set方法与Lombok生成的set方法,SpringBoot想用setcName映射属性,可是Lombok生成的是setCName,导致的问题。
// SpringBoot生成
@Data
public class User {
private String name;
@JsonAlias("cName")
private String cName;
private String URL;
private String isOK;
public void setcName(String cName) {
this.cName = cName;
}
}
// Lombok生成
public class User {
private String name;
@JsonAlias({"cName"})
private String cName;
private String URL;
private String isOK;
public void setCName(final String cName) {
this.cName = cName;
}
}