我们何时必须使用@ModelAttribute及其使用方法

时间:2019-10-10 20:01:22

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

你好,我对@ModelAttribute批注有疑问。据我了解,我们在方法参数中使用@ModelAttribute从模型中获取数据。但是,很难清楚地了解其使用时间和方式。 (代码示例摘自Spring in Action 5书) 为什么在这种情况下,在以下代码中,公共字符串processOrder()方法中,我们不对 @有效订单

使用@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:/";
      }


    }

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

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

在此代码段中(来自上面的代码):

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

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

2 个答案:

答案 0 :(得分:1)

文档对此非常清楚:

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

  

@ModelAttribute

     

用于访问模型中的现有属性(如果没有,则实例化   当前)并应用了数据绑定和验证。参见@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。通常,无论如何我都倾向于指定它。

答案 1 :(得分:0)

我也不清楚。

在这里,我们需要指定模型属性的名称。 因为我们认为我们将其命名为“ 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”   “列表”。