Spring: @ModelAttribute与@RequestBody的区别

80

如果我有错误,请纠正我。 两者均可用于数据绑定

问题是何时使用@ModelAttribute?

@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(@ModelAttribute Pet pet) { }

此外,何时使用 @RequestBody?

@RequestMapping(value = "/user/savecontact", method = RequestMethod.POST
public String saveContact(@RequestBody Contact contact){ }

根据我的理解,它们都有类似的作用。

谢谢!

10个回答

54

就我理解来说,@ModelAttribute将会获取查询字符串。因此,所有的数据都通过URL传递到服务器。

至于@RequestBody,所有的数据都通过一个完整的JSON体传递到服务器。


7
简单来说,@RequestBody指定请求体,@ResponseBody指定响应体。@ModelAttribute和@RequestParam用于从URL中解码查询参数。唯一的区别是@ModelAttribute将绑定所有字段并给出完整对象,但如果使用@RequestParam,则必须手动映射所有字段构建整个对象。详情请参见此处。 - amarnath harish
ModelAttribute和RequestParam用于解码URL中的查询参数 - 那么Get和Post HTTP方法是用来做什么的?使用Post,您的参数不会在URL中发送。 - Shweta Priyadarshani
@CharlesC - 所以ModelAttribute会从请求体中(使用POST方法)选择数据,格式为键值对的字符串,而RequestBody会选择JSON格式的数据? - Shweta Priyadarshani

22

@ModelAttribute 用于将请求参数(以键值对的形式)绑定到数据上,

@RequestBody 则用于将请求体中的数据绑定到数据上,例如 POST、PUT 等请求类型,其中包含其他格式,如 JSON、XML。


1
JSON也是键值对,那么JSON数据和请求参数有什么不同呢? - Shweta Priyadarshani

15

如果您想要进行文件上传,您必须使用@ModelAttribute。使用@RequestBody是不可能的。示例代码:

@RestController
@RequestMapping(ProductController.BASE_URL)
public class ProductController {

    public static final String BASE_URL = "/api/v1/products";

    private ProductService productService;

    public ProductController(ProductService productService) {
        this.productService = productService;
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public ProductDTO createProduct(@Valid @ModelAttribute ProductInput productInput) {
        return productService.createProduct(productInput);
    }

}

产品输入类

@Data
public class ProductInput {

    @NotEmpty(message = "Please provide a name")
    @Size(min = 2, max = 250, message = "Product name should be minimum 2 character and maximum 250 character")
    private String name;

    @NotEmpty(message = "Please provide a product description")
    @Size(min = 2, max = 5000, message = "Product description should be minimum 2 character and maximum 5000 character")
    private String details;

    @Min(value = 0, message = "Price should not be negative")
    private float price;

    @Size(min = 1, max = 10, message = "Product should have minimum 1 image and maximum 10 images")
    private Set<MultipartFile> images;
}

我确认也是。 - Hayi
1
你能详细说明请求调用应该是什么样子的吗?我发送了一个包含图片的请求,但我的对象中获取到的是空值。 - Ahmed Aziz
1
@AhmedAziz,我的对象也出现了空值,你能告诉我你是如何解决的吗? - Saurabh Jhunjhunwala

7

我发现@RequestBody(同时将类注释为@RestController)更适用于AJAX请求,其中您完全控制发出的请求内容,并且内容以XML或JSON(由于Jackson)发送。这允许内容轻松创建模型对象。相反,@ModelAttribute似乎更适用于表单,其中存在支持表单的“command”对象(可能不一定是模型对象)。


6
如果您使用ModelAttribute注释,可以直接在视图层中访问您的“pet”对象。此外,您还可以在控制器上的方法中实例化此对象以放置您的模型。请参见此处ModelAttribute使您有机会部分使用此对象,但使用RequestBody,您将获得请求的所有正文。

2

我认为@ModelAttribute和@RequestBody具有相同的用途,唯一的区别是@ModelAttribute用于普通的Spring MVC,而@RequestBody用于REST Web服务。这类似于@PathVariable和@PathParam。但在这两种情况下,我们都可以混合使用。我们可以在REST中使用@PathVariable,反之亦然。


0
我们需要使用以下JSP标签将实体数据绑定到JSP表单字段:
该表单来自Spring标签库:
以下不是完整的HTML代码,但我希望您能够理解:
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>

        <form:form action="save" method="post" modelAttribute="patient">
            <table>
                <tr>
                    <td>Name</td>
                    <td>
                        <form:input path="patient.patient_name"  /> <br />
                        
                    </td>
                </tr>
                <tr>
                    <td>Phone</td>
                    <td>
                        <form:input path="patient.phone_number" /> <br />
                    </td>
                </tr>
                <tr>
                    <td colspan="2"><button type="submit">Submit</button></td>
                </tr>
            </table>
        </form:form>

表单需要处理两次,一次是在呈现表单之前,我们需要为属性值modelAttribute="patient"提供适当的bean实例化。

  1. 为此,控制器类(在类定义级别)需要有@RequestMapping注释。
  2. 您需要按以下方式设置处理程序方法参数
@GetMapping("logincreate")

public String handleLoginCreate(@ModelAttribute("login") Login login, Model model)
{
    System.out.println(" Inside handleLoginCreate  ");
    model.addAttribute("login",login);
    return "logincreate";
}

Spring将扫描所有处理程序方法@ModelAttribute,并使用Login类的默认构造函数对其进行实例化,并调用其所有getter和setter(用于在表单与“login”之间进行jsp绑定)。如果缺少以下任何一个,则不会显示jsp,会抛出各种异常

  1. getters/setters
  2. 默认构造函数
  3. model.addAttribute("login",login);
  4. 类级别的@RequestMapping
  5. 方法参数级别的@ModelAttribute

此外,在jsp中的操作处理程序方法,在上述形式中 action="save",处理程序方法可能如下所示:

@PostMapping("save")

public String saveLoginDetails(@ModelAttribute("login") Login login, Model model) {
    
    //write codee to insert record into DB
    System.out.println(" Inside save login details  ");
    System.out.println("The login object is " + login.toString());
    System.out.println("The model object contains the login attribute"+ model.getAttribute("login"));   
    loginService.saveLogin(login);
    return "welcome";
}

重要的学习内容是:

  1. 在表单启动之前,Spring 应该有适当的注释来指示表单的支持 bean,在上面的例子中,“支持 bean” 或 “绑定对象” 是具有适当处理程序方法参数注释 @ModelAttribute("login") Login login 的登录。

0
使用 @ModelAttribute,您可以通过URL参数传递数据,而使用 @RequestBody,则将其作为JSON主体传递。如果您正在创建一个REST API,最好使用 @RequestBody。在大多数YouTube教程中,您可能会发现使用 @ModelAttribute - 这仅仅是因为他们可能正在演示有关Spring MVC的概念,并且正在使用URL来传递数据。

无论是否使用@ModelAttribute,传递数据到URL参数取决于所使用的HTTP方法。使用POST方法时,参数将不会在URL中传递,而是在请求正文中传递。 - Shweta Priyadarshani

0
@ModelAttribute基本上是在你想要将多部分文件包含在请求体中时使用的。为了从前端传递数据,你需要将数据转换为JSON格式。即使编写测试用例也有一些不同之处。你需要使用contentType(MediaType.APPLICATION_FORM_URLENCODED)作为内容类型,并且不再使用JSON字符串,而是将值作为.param("field", value)传递。

0
@RequestBody: 此注解用于将整个请求体绑定到方法参数上。通常在请求负载为JSON或XML格式时使用。
@PostMapping("/example")
public ResponseEntity<String> handleRequest(@RequestBody ExampleDto exampleDto) {
   // Do something with the exampleDto object
   return ResponseEntity.ok("Request handled successfully");
}
@ModelAttribute:这个注解用于将请求参数(无论是在查询字符串中还是在表单数据中)绑定到方法参数或模型属性。它通常与HTML表单一起使用,或者当您想从请求中提取单个参数时使用。
@PostMapping("/example")
public ResponseEntity<String> handleRequest(@ModelAttribute("name") String name, @ModelAttribute("age") int age) {
    // Do something with the name and age parameters
    return ResponseEntity.ok("Request handled successfully");
}

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