【问题标题】:Spring: @ModelAttribute VS @RequestBody春天:@ModelAttribute VS @RequestBody
【发布时间】:2014-03-16 10:47:49
【问题描述】:

如果我错了,请纠正我。 两者都可用于数据绑定

问题是什么时候使用@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){ }

据我了解,两者的目的相似。

谢谢!!

【问题讨论】:

    标签: spring spring-mvc data-binding


    【解决方案1】:

    如果你使用ModelAttribute注解,你可以在view layer中直接访问你的“pet”对象。此外,您可以在控制器上的方法中实例化此对象以放置模型。 see this

    ModelAttribute 让您有机会使用此对象的部分,但使用 RequestBody,您可以获得所有请求正文。

    【讨论】:

      【解决方案2】:

      @ModelAttribute 用于绑定来自请求参数的数据(在键值对中),

      @RequestBody 用于绑定来自整个请求体的数据,如 POST、PUT.. 包含其他格式(如 json、xml)的请求类型。

      【讨论】:

      • JSON 也是 key value only ,JSON 数据与请求参数有何不同?
      【解决方案3】:

      据我了解,最简单的方法是,@ModelAttribute 将采用查询字符串。因此,所有数据都通过 url 传递到服务器。

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

      【讨论】:

      • 简单地说@RequestBody 指定了请求的主体。 @ResponseBody 指定响应的正文。 @ModelAttribute@RequestParam 用于从 URL 解码查询参数。唯一的区别是 @modelAttribute 将绑定所有字段并给出一个完整的对象。但是如果您使用 @RequestParam 您已经通过手动映射所有字段来构建整个对象。欲了解更多信息see here
      • ModelAttribute 和 RequestParam 用于从 URL 解码查询参数 - 那么 Get 和 Post HTTP 方法有什么用?使用 Post ,您的参数不会在 URL 中发送
      • @CharlesC - 所以 ModelAttribute 将从请求正文(使用 POST 方法)中以键值对字符串的形式选择数据,而 RequestBody 将选择 JSON 格式的数据?
      【解决方案4】:

      我发现@RequestBody(也将类注释为@RestController)更适合AJAX请求,您可以完全控制发出的请求的内容并且内容以XML或JSON的形式发送(因为Jackson) .这允许内容轻松创建模型对象。相反,@ModelAttribute 似乎更适合有支持表单的“命令”对象(可能不一定是模型对象)的表单。

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

          如果你想上传文件,你必须使用@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);
              }
          
          }
          

          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;
          }
          

          【讨论】:

          • 我也确认了
          • 您能否详细说明请求调用的外观?我正在发送一个带有图像的请求,但我的对象中得到了空值。
          • @AhmedAziz 我的对象中也有空值,你能帮我解决这个问题吗
          【解决方案7】:

          使用@ModelAttribute,您可以在URL 参数中传递数据,而使用@RequestBody,您可以将其作为JSON 正文传递。如果您正在制作 REST API,那么最好使用 @RequestBody。在大多数 youtube 教程中,您可能会发现使用 @ModelAttribute - 这仅仅是因为它们可能正在演示有关 Spring MVC 的概念并使用 URL 来传递数据。

          【讨论】:

          • 是否在 URL 参数中传递数据取决于使用的 HTTP 方法而不是 @ModelAttribute 使用 Post ,参数不会在 URL 中传递,而是在请求正文中传递
          【解决方案8】:

          我们需要使用以下 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. 你需要有handler方法参数如下
          @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(用于从表单到“登录”的 jsp 绑定)。如果缺少以下任何一项,jsp都不会显示,会抛出各种异常

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

          另外,jsp中action的handler方法,如上式action="save",handler方法也可能是这样的:

          @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应该有适当的注解来指示表单的backing bean,在上面的例子中,“backing bean”或“binding object”是Login login,带有适当的handler方法的参数注解@ModelAttribute("login") Login login

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-02-20
            • 1970-01-01
            • 2023-03-12
            • 2019-10-04
            • 2014-01-30
            • 2011-09-23
            • 2021-06-10
            相关资源
            最近更新 更多