Spring MVC @ModelAttribute @SessionAttributes - 为什么模型属性需要@ModelAttribute注释方法?

时间:2013-11-10 13:23:03

标签: java spring spring-mvc modelattribute

这就是现在的样子:

@SessionAttributes("shoppingCart")
public class ItemController {

    @ModelAttribute
    public ShoppingCart createShoppingCart() {
        return new ShoppingCart();
    }

    @RequestMapping(value=RequestMappings.ADD_TO_CART + RequestMappings.PARAM_ITEM_ID, method=RequestMethod.GET)
    public String addToCart(@PathVariable("itemId") Item item, @ModelAttribute ShoppingCart shoppingCart) {

        if(item != null) {
            shoppingCartService.addItem(shoppingCart, item);
        }

        return ViewNamesHolder.SHOPPING_CART;
    }
}

首次调用addToCart方法时,shoppingCart对象将由createShoppingCart方法初始化。在运行addToCart方法之后,初始化的对象将被添加到会话中,并将从会话中使用它以供以后使用。这意味着createShoppingCart方法只被调用一次(只要它不从会话中删除)。

为什么Spring只需要在需要时创建这个对象,就不需要使用ModelAttribute注释的初始化方法?然后它看起来会更简单:

@SessionAttributes("shoppingCart")
public class ItemController {

    @RequestMapping(value=RequestMappings.ADD_TO_CART + RequestMappings.PARAM_ITEM_ID, method=RequestMethod.GET)
    public String addToCart(@PathVariable("itemId") Item item, @ModelAttribute ShoppingCart shoppingCart) {

        if(item != null) {
            shoppingCartService.addItem(shoppingCart, item);
        }

        return ViewNamesHolder.SHOPPING_CART;
    }
}

每当在会话中找不到shoppingCart对象时,它将由其默认构造函数初始化。 你认为这个决定的原因是什么?

1 个答案:

答案 0 :(得分:1)

我不能直接为Spring团队发言,但是您的建议会将所需的ModelAttribute限制为每个请求上的新创建的实例(在存储到会话之前),但是如果您想要完全开始例如,从数据存储中获取的填充对象?你的方法无法做到这一点。然而,这很有效:

@ModelAttribute
public ShoppingCart createShoppingCart() {
    ...
    return someShoppingCartRepo.find(...);
}

当然,这只是一种可能的情况,其中单独方法的有用性应该是显而易见的。

评论后编辑

您可以轻松创建自己的HandlerMethodArgumentResolver,如果不存在,则可以为您提供对象的新实例,但考虑到使用createShoppingCart()方法有多容易,可能会有些过分。如果你使用xml配置,它将是这样的:

<mvc:annotation-driven ...>
    <mvc:argument-resolvers>
        <bean class="yourpackage.YourCustomArgumentResolver" />
    </mvc:argument-resolvers>
</mvc:annotation-driven>

您可以扩展任意数量的现有HandlerMethodArgumentResolver基类,或者您可以直接自己实现该接口,但很可能您会使用以下内容:

public class YourCustomArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
    // Implement/override methods for creating your model object when encountered as a method argument
}

要识别您的参数,您可以创建自定义注释:

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface YourAutoCreateModelAttribute {

    String value() default "";

    boolean required() default true;

    String defaultValue() default ValueConstants.DEFAULT_NONE;
}

然后注释您的方法,以启动您的自定义解析器:

@RequestMapping(...)
public String doStuff(@YourAutoCreateModelAttribute ShoppingCart shoppingCart, ...) {
    // Now your shoppingCart will be created auto-magically if it does not exist (as long as you wrote your resolver correctly, of course.
}