Spring MVC: @RequestBody与@ModelAttribute的区别

8
我理解您的意思是,在Spring MVC应用程序中,为了捕获/数据绑定HTTP请求的正文,可以使用@RequestBody,对于以application/json编码的请求,是这样吗?
@PostMapping(consumes = "application/json")
public String handleUpload( @RequestBody UploadCommand command ) {
     // ...   
}

@ModelAttribute

这个注解用于处理编码为x-www-form-urlencoded或者multipart/form-data的请求数据。

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

问题:

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

这些注解还有其他用途吗?

注意: 经过一番搜索,这个stackoverflow答案深入阐述了@ModelAttribute: @ModelAttribute注释,何时使用?


因为它们是两个完全不同的东西。从JSON创建对象与从请求参数绑定是完全不同的,因此需要使用不同的注释。 - M. Deinum
@M. Deinum 查询部分的URL(?..)也可以使用ModelAttribute映射为单个对象吗? - Dachstein
这就是@ModelAttribute的全部意义所在,可以是查询参数或表单参数。 - M. Deinum
1
@ModelAttribute 对数据绑定没有任何作用。您可以删除此注释,但数据仍将被绑定。@ModelAttribute 只是检查标记的对象是否已经存在于模型中,如果不存在则创建一个新的对象。 - Ken Bekov
1
最大的区别在于 @RequestBody 使用了 messageConverter,而 @ModelAttribute 没有。 - akuma8
显示剩余3条评论
1个回答

9

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

这两个注解是为了应对不同的应用场景而创建的。
- @RequestBody 适用于restful应用程序
- @ModelAttribute 适用于web mvc应用程序

它们有什么区别?

假设您有一个Java类UserData:

public class UserData {

    private String firstName;
    private String lastName;

    //...getters and setters
} 

您希望使用此用户数据进行请求并映射到对象字段。 @RequestBody 用于消耗请求正文,并通过 HttpMessageConverter 反序列化为对象。您可以在此注释中指定“consumes”,以提供 @PostMapping 可接受的数据类型。
参考:https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-requestbody 示例:POST 请求中包含用户数据 JSON 正文。
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"}

您可以通过在方法参数上使用 @RequestBody 注解来简单地注释,所有数据将转换为您的模型。
@PostMapping("/user")
public void getUserData( @RequestBody UserData userData) {
     // ...   
}

否则,您必须将请求作为字符串消耗,并手动进行反序列化:
ObjectMapper objectMapper = new ObjectMapper();
UserData userData = objectMapper.readValue(postBody, UserData.class)

@ModelAttribute 是对 ServletRequest 的增强,它能够帮助你避免处理单个查询参数和表单字段的解析和转换。你只需使用此注释注解你的请求体,就不需要再做这些事情:

String firstName= req.getParameter("firstName"); // req is HttpServletRequest
String lastName= req.getParameter("lastName"); // req is HttpServletRequest

所有数据将由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>

此表单将由Web浏览器转换为以下请求,并由Spring消费:
POST / HTTP/2.0
Host: foo.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 13

firstName=Tyrion&lastName=Lannister

Spring MVC控制器的示例:

@PostMapping("/user")
public void getUserData( @ModelAttribute UserData userData ) {
     // ...   
}

好的解释!谢谢!三年后我仍然学到了东西,值得。 - Dachstein
@Dachstein,哈哈=)我回答了它的历史=)我看到它有很多浏览量,所以很多人都有和你一样的问题)如果一切正确,你可以将其标记为答案;-) - Dmitrii Cheremisin

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