Spring MVC:@RequestBody VS @ModelAttribute

Dac*_*ein 8 data-binding spring annotations spring-mvc

我是否理解正确,为了在 Spring MVC 应用程序中捕获/数据绑定 HTTP 请求的主体,有人可以使用...

@RequestBody

application/json对于编码为?的请求

@PostMapping(consumes = "application/json")
public String handleUpload( @RequestBody UploadCommand command ) {
     // ...   
}
Run Code Online (Sandbox Code Playgroud)

@ModelAttribute

x-www-form-urlencoded对于编码为或multipart/form-data?的请求

@PostMapping(consumes = "multipart/form-data")
public String handleUpload( @ModelAttribute UploadCommand command ) {
     // ...   
}
Run Code Online (Sandbox Code Playgroud)

问题:

为什么Spring需要有这两个不同的注解呢?

这些注释还有其他用例吗?

注意: 经过深入研究:这个 stackoverflow 答案深入阐述了 @ModelAttribute: @ModelAttribute 注释,何时使用它?

小智 9

Why is it necessary for Spring to have those two different annotations?

为不同的应用程序类型创建两个注释。
- @RequestBody 用于 Restfull 应用程序
- @ModelAttribute 用于 Web MVC 应用程序

他们有什么区别?

假设你有一个java类UserData:

public class UserData {

    private String firstName;
    private String lastName;

    //...getters and setters
} 
Run Code Online (Sandbox Code Playgroud)

您希望使用此用户数据来使用请求并映射到您的对象字段。

@RequestBody用于使用请求正文并通过 HttpMessageConverter 反序列化为对象。您可以通过在此注释中指定“consumes”来提供 @PostMapping 可以接受的数据类型。

参考:https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-requestbody

带有用户数据 json 正文的 POST 请求示例:

POST /api/v1/auth HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-Length: 40
Accept: application/json, text/plain, */*
Content-Type: application/json

{"firstName":"Tyrion","lastName":"Lannister"}
Run Code Online (Sandbox Code Playgroud)

您可以简单地使用注释@RequestBody注释您的方法参数,所有数据都将在您的模型中转换

@PostMapping("/user")
public void getUserData( @RequestBody UserData userData) {
     // ...   
}
Run Code Online (Sandbox Code Playgroud)

否则,您必须将请求作为字符串使用,然后自己手动进行反序列化:

ObjectMapper objectMapper = new ObjectMapper();
UserData userData = objectMapper.readValue(postBody, UserData.class)
Run Code Online (Sandbox Code Playgroud)

@ModelAttribute是 ServletRequest 的增强功能,使您不必处理解析和转换单个查询参数和表单字段。您只需使用此注释来注释您的请求正文,无需再执行此操作:

String firstName= req.getParameter("firstName"); // req is HttpServletRequest
String lastName= req.getParameter("lastName"); // req is HttpServletRequest
Run Code Online (Sandbox Code Playgroud)

所有数据将由spring自动转换。

参考: https: //docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-modelattrib-method-args

此请求的表格示例如下:

<form action="yourEndpoint" method="POST">
    <input name="firstName" id="firstName" value="Tyrion">
    <input name="lastName" id="lastName" value="Lannister">
    <button>Submit</button>
</form>
Run Code Online (Sandbox Code Playgroud)

该表单将由 Web 浏览器转换为以下请求,并由 spring 使用:

POST / HTTP/2.0
Host: foo.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 13

firstName=Tyrion&lastName=Lannister
Run Code Online (Sandbox Code Playgroud)

spring mvc 控制器示例:

@PostMapping("/user")
public void getUserData( @ModelAttribute UserData userData ) {
     // ...   
}
Run Code Online (Sandbox Code Playgroud)