When we must use @ModelAttribute, and how it works

安稳与你 提交于 2020-06-12 11:43:51

问题


Hello I have question about @ModelAttribute annotation. As i understand, we use @ModelAttribute in method arguments to get data from the model. But it's quite hard to understand clearly when and how its used. (Code samples are from Spring in Action 5 book) Why in this case in the code below in public String processOrder() method we do not use @ModelAttribute annotation on @Valid Order order

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


    }

but in this case, DesignTacoController class, @ModelAttribute on a method processDesign() is used on @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";
      }

And then in the next chapter author removes @ModelAttribute from processDesign() method from the same DesignTacoController class.

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

And in this code snippet(from the code above):

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

quote from book: "The Order parameter is annotated with @ModelAttribute to indicate that its value should come from the model and that Spring MVC shouldn’t attempt to bind request parameters to it." This I don't understand what author meant here, because in all tutorials it is said that when @ModelAttribute is used as a method arguments,it binds request parameters to it. Binds the form data with a POJO bean, model attribute is populated with data from a form submitted.


回答1:


The documentation is pretty clear on this:

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

@ModelAttribute

For access to an existing attribute in the model (instantiated if not present) with data binding and validation applied. See @ModelAttribute as well as Model and DataBinder.

Note that use of @ModelAttribute is optional (for example, to set its attributes). See “Any other argument” at the end of this table.

.

Any other argument

If a method argument is not matched to any of the earlier values in this table and it is a simple type (as determined by BeanUtils#isSimpleProperty, it is a resolved as a @RequestParam. Otherwise, it is resolved as a @ModelAttribute.

So essentially it is optional. You may wish to use just to make it explicit that that is how the argument is resolved or you may need to use if binding should not happen (by specifying binding = false) See futher: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ModelAttribute.html. It is normally my preference to specify it regardless.




回答2:


This wasn't clear to me either.

Here we need specify the name if the model attribute. Because in our view we assume it is named "design" and not "taco".

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

If we rename the Taco class to Design ... We don't need to specify the name if the model attribute. It will be deduced from the simple name of the class. com.example.Design -> "design"

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

See the javadoc for ModelAttribute:

The default model attribute name is inferred from the declared attribute type (i.e. the method parameter type or method return type), based on the non-qualified class name: e.g. "orderAddress" for class "mypackage.OrderAddress", or "orderAddressList" for "List".



来源:https://stackoverflow.com/questions/58330323/when-we-must-use-modelattribute-and-how-it-works

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!