【问题标题】:When we must use @ModelAttribute, and how it works何时必须使用@ModelAttribute,以及它是如何工作的
【发布时间】:2020-02-08 08:04:15
【问题描述】:

您好,我对@ModelAttribute 注释有疑问。据我了解,我们在方法参数中使用 @ModelAttribute 从模型中获取数据。但是很难清楚地理解它何时以及如何使用。 (代码示例来自 Spring in Action 5 书) 为什么在这种情况下,在 public String processOrder() 方法的下面代码中,我们不在 @Valid Order order

上使用 @ModelAttribute 注释
    @Controller
    @RequestMapping("/orders")
    @SessionAttributes("order")
    public class OrderController {

      private OrderRepository orderRepo;

      public OrderController(OrderRepository orderRepo) {
        this.orderRepo = orderRepo;
      }

      @GetMapping("/current")
      public String orderForm(@AuthenticationPrincipal User user, 
          @ModelAttribute Order order) {
        if (order.getDeliveryName() == null) {
          order.setDeliveryName(user.getFullname());
        }
        //following conditions

        return "orderForm";
      }


      @PostMapping
      public String processOrder(@Valid Order order, Errors errors,  // <<< Here
          SessionStatus sessionStatus, 
          @AuthenticationPrincipal User user) {

        if (errors.hasErrors()) {
          return "orderForm";
        }

        order.setUser(user);

        orderRepo.save(order);
        sessionStatus.setComplete();

        return "redirect:/";
      }


    }

但在这种情况下,DesignTacoController 类,方法 processDesign() 上的@ModelAttribute 用于@Valid Taco taco:

    @Slf4j
    @Controller
    @RequestMapping("/design")
    public class DesignTacoController {



      @PostMapping
 public String processDesign(@Valid @ModelAttribute("design") Taco design, // <<< Here   
 Errors errors, Model model) {
        if (errors.hasErrors()) {
          return "design";
        }

        // Save the taco design...
        // We'll do this in chapter 3
        log.info("Processing design: " + design);

        return "redirect:/orders/current";
      }

然后在下一章作者从同一 DesignTacoController 类的 processDesign() 方法中删除 @ModelAttribute。

    @Controller
    @RequestMapping("/design")
    @SessionAttributes("order")
    @Slf4j
    public class DesignTacoController {

      @ModelAttribute(name = "order")
      public Order order() {
        return new Order();
      }

      @ModelAttribute(name = "design")
      public Taco design() {
        return new Taco();
      }


      @PostMapping
      public String processDesign(
          @Valid Taco taco, Errors errors, // <<< Here 
          @ModelAttribute Order order) {

        log.info("   --- Saving taco");

        if (errors.hasErrors()) {
          return "design";
        }

        Taco saved = tacoRepo.save(taco);
        order.addDesign(saved);

        return "redirect:/orders/current";
      }

在这段代码中 sn-p(来自上面的代码):

    @PostMapping
          public String processDesign(
              @Valid Taco taco, Errors errors, // <<< Here 
              @ModelAttribute Order order) {
    ....
    }

书上的引用:“Order 参数用@ModelAttribute 注释以表明它的 值应该来自模型并且 Spring MVC 不应该尝试绑定 向它请求参数。” 这个我不明白作者在这里的意思,因为在所有教程中都说当@ModelAttribute用作方法参数时,它会将请求参数绑定到它。使用 POJO bean 绑定表单数据,模型属性填充来自提交的表单的数据。

【问题讨论】:

  • 对于您对书中报价的查询,您可以在这里找到答案。 stackoverflow.com/a/42198051/2825798
  • 1.我不明白我们什么时候使用 Valid ModelAttribute Object 对象,什么时候 Valid Object 对象就足够了。 2/3。在您的链接中,据说“ModelAttribute 用于绑定来自请求参数的数据”,我从书中引用说我们使用 ModelAttribute“Spring 不应该尝试绑定请求参数”。我不明白,因为对我来说这两个引用相互矛盾

标签: java spring spring-boot spring-mvc modelattribute


【解决方案1】:

文档对此非常清楚:

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

@ModelAttribute

用于访问模型中的现有属性(如果没有,则实例化 present) 应用了数据绑定和验证。请参阅@ModelAttribute 以及 Model 和 DataBinder。

注意@ModelAttribute 的使用是可选的(例如,设置它的 属性)。请参阅本表末尾的“任何其他论点”。

.

任何其他论点

如果方法参数与之前的任何值都不匹配 此表是一个简单类型(由 BeanUtils#isSimpleProperty,它被解析为@RequestParam。 否则,它被解析为@ModelAttribute

所以本质上它是可选的。您可能希望使用它来明确说明这是如何解析参数的,或者您可能需要使用如果绑定不应该发生(通过指定binding = false)请参阅:https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ModelAttribute.html。无论如何,我通常倾向于指定它。

【讨论】:

  • 谢谢艾伦·海。我还没有弄清楚 Spring in Action 5 书中关于 qoute 的最后一个问题。我不明白作者所说的“Order 参数用 ModelAttribute 注释以表明它的值应该来自模型和 Spring MVC不应尝试将请求参数绑定到它。”但是我读到的所有地方都说 ModelAttribute 用于绑定来自请求参数的数据。这不是和作者写的相反吗?我没有得到什么?
  • 我只能假设作者通过指定binding=false 阻止了绑定。在这种情况下(即使用模型属性作为参数但没有绑定)您必须指定 @ModelAttribute docs.spring.io/spring/docs/current/javadoc-api/org/…
【解决方案2】:

我也不清楚。

这里我们需要指定模型属性的名称。 因为在我们看来,我们假设它被命名为“design”而不是“taco”。

@PostMapping
public String processDesign(@Valid @ModelAttribute("design") Taco design, Errors errors) {

如果我们将 Taco 类重命名为 Design ... 如果是模型属性,我们不需要指定名称。 它将从类的简单名称中推断出来。 com.example.Design -> "design"

@PostMapping
public String processDesign(@Valid Design design, Errors errors) {

javadoc for ModelAttribute

默认模型属性名称是从声明的 属性类型(即方法参数类型或方法返回类型), 基于非限定类名:例如类的“orderAddress” “mypackage.OrderAddress”或“orderAddressList” “列表”。

【讨论】:

    猜你喜欢
    • 2015-05-28
    • 1970-01-01
    • 2011-10-27
    • 1970-01-01
    • 1970-01-01
    • 2015-04-04
    • 2011-11-17
    相关资源
    最近更新 更多