【问题标题】:Why is @ModelAttribute not needed here?为什么这里不需要@ModelAttribute?
【发布时间】:2021-04-12 13:27:08
【问题描述】:

我是 Spring 新手,正在阅读“Spring in Action”(这确实是一本好书)。 在这里,我在本书的一个例子中遇到了一个让我很困惑的问题。 在这个example中,有两个控制器分别对应两个路径。一个是 DesignTacoController,另一个是 OrderController。

在我自己试验这个例子的过程中,我首先复制了 OrderController,它是一个非常简单的类,如下所示。当网页上有is/isn't错误输入时,这段代码可以完美运行。

@Slf4j
@Controller
@RequestMapping("/orders")
public class OrderController {

    @GetMapping("/current")
    public String orderForm(Model model) {
        model.addAttribute("order", new Order());
        return "orderForm";
    }

    @PostMapping
    public String processOrder(@Valid Order order, Errors errors) {
        if (errors.hasErrors()) {
            return "orderForm";
        }
        log.info("Order submitted: " + order);
        return "redirect:/";
    }
}

然后我按照上面的OrderController自己实现了DesignTacoController

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

    @GetMapping
    public String showDesignForm(Model model) {
        List<Ingredient> ingredients = Arrays.asList(
                // adding some ingredients
        );
        Type[] types = Ingredient.Type.values();
        for (Type type: types) {
            model.addAttribute(
                    type.toString().toLowerCase(Locale.ROOT),
                    filterByType(ingredients, type));
        }
        model.addAttribute("design", new Taco());
        return "design";
    }

    @PostMapping
    public String processDesign(@Valid Taco design, Errors errors) {
        if (errors.hasErrors()) {
            return "design";
        }
        log.info("Processing design: " + design);
        return "redirect:/orders/current";
    }

    // more methods ignored
}

使用此实现,当没有错误输入时它可以正常工作。但是,如果我对验证器输入一些内容,我会得到一个

java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'design' available as request attribute

通过在stackoverflow(this question)上搜索并检查github上的original example code,我发现这个类应该这样实现

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


    @ModelAttribute
    public void addIngredientsToModel(Model model) {
        List<Ingredient> ingredients = Arrays.asList(
            // adding some ingredients
        );

        Type[] types = Ingredient.Type.values();
        for (Type type : types) {
        model.addAttribute(type.toString().toLowerCase(),
            filterByType(ingredients, type));
        }
    }

    @GetMapping
    public String showDesignForm(Model model) {
        model.addAttribute("design", new Taco());
        return "design";
    }

    @PostMapping
    public String processDesign(@Valid @ModelAttribute("design") Taco design, 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";
    }
    // more methods ignored
}

我的问题来了,

  1. 为什么即使不使用@ModelAttribute 注解,OrderController 也能正常工作?
  2. 为什么我们在 DesignTacoController 中需要 @ModelAttribute
  3. addIngredientsToModel 何时被调用?
  4. 我们可以合并 addIngredientsToModel 和 showDesignForm 吗?

我认为我缺少一些 Spring 的基本概念。希望有人能帮我解决这个问题。

非常感谢。

【问题讨论】:

  • 我很困惑,当有 are 错误时,订单示例是否有效?
  • @crizzis 是的。这也是让我感到困惑的地方。 :)

标签: spring spring-mvc


【解决方案1】:

在方法级别使用@ModelAttribute 时,目的是为模型添加一个或多个模型属性。这里添加这个

到模型。 model.addAttribute(type.toString().toLowerCase(), filterByType(ingredients, type)); }

问题是 Spring 在任何请求映射之前创建模型对象。所以 addIngredientsToModel 方法会在任何 Handler 方法之前被调用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-03
    • 1970-01-01
    • 2021-08-27
    • 1970-01-01
    • 1970-01-01
    • 2010-12-15
    • 2019-01-16
    • 2021-10-22
    相关资源
    最近更新 更多