【问题标题】:Spring MVC: @RequestBody VS @ModelAttributeSpring MVC:@RequestBody VS @ModelAttribute
【发布时间】:2017-05-01 09:11:28
【问题描述】:

为了在 Spring MVC 应用程序中捕获/数据绑定 HTTP 请求的 body,我是否理解正确...

@RequestBody

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

@PostMapping(consumes = "application/json")
public String handleUpload( @RequestBody UploadCommand command ) {
     // ...   
}

@ModelAttribute

对于编码为x-www-form-urlencodedmultipart/form-data 的请求?

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

问题:

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

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

注意: 在挖掘之后:这个stackoverflow答案详细阐述了@ModelAttribute: @ModelAttribute annotation, when to use it?

【问题讨论】:

  • 因为两者是完全不同的野兽。从 JSON 创建对象与从请求参数绑定完全不同。因此不同的注释。
  • @M. Deinum url (?..) 的查询部分是否也可以与 ModelAttribute 映射(到单个对象中)?
  • 这就是@ModelAttribute 的全部意义所在。可以是查询或表单参数。
  • @ModelAttribute 对数据绑定没有任何作用。您可以删除此注释,但无论如何数据都会被绑定。 @ModelAttribute 只需检查标记的对象是否已经在模型中,如果没有则创建新的。
  • 最大的区别是@RequestBody 使用messageConverter@ModelAttribute 不使用。

标签: spring spring-mvc data-binding annotations


【解决方案1】:

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
} 

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

@RequestBody 用于消费请求体,并通过 HttpMessageConverter 反序列化为 Object。您可以通过在此注解中指定“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"}

您可以简单地使用注解@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>

这个表单会被浏览器转换成下面的请求,由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 ) {
     // ...   
}

【讨论】:

  • 很好的解释!谢谢! 3年后我问了这个问题,我仍然学到了一些东西。
  • @Dachstein, 哈哈 =) 我为历史回答了=) 我看到它有很多观点,所以很多人和你有同样的问题) 你可以将它标记为答案如果一切是正确的;-)
猜你喜欢
  • 2014-03-16
  • 2020-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-20
  • 2017-11-27
  • 2018-06-30
相关资源
最近更新 更多