Spring MVC - HttpSession.setAttribute 和 model.addObject 之间的区别

Posted

技术标签:

【中文标题】Spring MVC - HttpSession.setAttribute 和 model.addObject 之间的区别【英文标题】:Spring MVC - difference between HttpSession.setAttribute and model.addObject 【发布时间】:2013-04-29 07:19:07 【问题描述】:

我最近正在尝试学习 Spring MVC。 @ModelAttribute 注解和 HttpSession 的功能我好像不太了解。

@SessionAttributes("shoppingCart", "count")
public class ItemController 

@ModelAttribute("shoppingCart")
public List<Item> createShoppingCart() 
    return new ArrayList<Item>();


@ModelAttribute("count")
public Integer createCount() 
    return 0;


@RequestMapping(value="/addToCart/itemId", method=RequestMethod.GET)
public ModelAndView addToCart(@PathVariable("itemId") Item item, 
        @ModelAttribute("shoppingCart") List<Item> shoppingCart, @ModelAttribute("count") Integer count) 

    if(item != null) 
        shoppingCart.add(item);
        count = count + 1;
    

    return new ModelAndView(new RedirectView("showAllItems")).addObject("count", count);


@RequestMapping(value="/deleteFromCart/itemId", method=RequestMethod.GET)
public ModelAndView deleteFromCart(@PathVariable("itemId") Item item, 
        HttpSession session) 

    List<Item> list = (List<Item>) session.getAttribute("shoppingCart");
    list.remove(item);
    //session.setAttribute("shoppingCart", list);

    Integer count = (Integer) session.getAttribute("count");
    count = count - 1;
    session.setAttribute("count", count);

    return new ModelAndView(new RedirectView("showAllItems"));

ShoppingCart 和 count 是会话属性。

问题出在 deleteFromCart 方法中。我从会话中获取 count重新分配它并在会话中覆盖它。但我 看不到 jsp 上 count 的更新值。但是,可以看到更新后的 shoppingCart 对象已更新,尽管我没有覆盖会话对象(因为该对象与已经在会话中的对象相同)。

但是为什么计数没有更新,虽然我用 session.setAttribute 覆盖了它? 当我将新的计数对象添加到模型(model.addObject(“count”,count))时,我可以看到更新的计数值。但是为什么 session.setAttribute 没有给出相同的结果呢?

【问题讨论】:

【参考方案1】:

model.addObject 将对象放入请求范围,而HTTPsession.setAttribute 将其放入会话范围。并且由于 jsp 上的变量是按下一个顺序解析的:页面范围 -> 请求范围 -> 会话范围 -> 应用范围,所以你得到了你得到的。

【讨论】:

但是我已经使用@SessionAttributes("warenkorb", "count") 将这两个属性定义为上面的会话属性。当我用 session.setAttribute("count", count) 覆盖属性计数时,它不应该用会话范围更改属性吗?也许我不应该把问题写成“setAttribute 和 addObject 之间的区别”,而是 deleteFromBasket 方法中使用的 2 个会话对象之间的区别,这两者都导致不同的方式(warenkorb 已更新,count 仍然是旧的 count 对象) . Fuh,终于解决了.. 将您的方法签名更改为public ModelAndView deleteFromBasket(@PathVariable Integer position, @ModelAttribute("warenkorb") List&lt;Item&gt; warenkorb, @ModelAttribute("count") Integer count, ModelMap modelMap) 并在会话中设置属性:modelMap.addAttribute("count", --count); 当我在你写的时候改变方法签名时,我知道它可以工作:) 我的 addToBasket 方法的工作方式相同。我只是想理解一般概念,尝试使用不同的东西,比如 HttpSession等等。不过,非常感谢。【参考方案2】:

首先,@SessionAttribute 不必使用 http 会话。它使用SessionAttributeStore,它可以有任何东西作为其后备存储。只有默认实现使用 http 会话。

您的代码无法按预期运行的原因在于@SessionAttribute 的工作原理。

在调用控制器方法之前,从会话中读取@SessionAttributes(在您的情况下为"warenkorb", "count")中列出的所有内容并添加到模型中。

方法返回后会话会更新为方法中添加到模型的所有内容。

.addObject("count", count)

-> 计数被添加到模型中,然后添加到会话中。

session.setAttribute("count", count)

-> 计数被添加到会话而不是模型。它将在下一次调用任何控制器方法之前添加到模型中。但就目前而言,该模型仍然具有旧的count。模型是添加到请求中的内容。如果可以在请求范围内找到属性,则 jsp 不关心会话中的内容。

当你使用@SessionAttributes@ModelAttribute(或一般的Spring MVC)时,请避免使用HttpSessionHttpRequest。甚至HttpResponse 的用途也有限。拥抱Spring MVC的美丽吧:)

【讨论】:

所以基本上;在调用控制器方法之前,会话会更新模型。在该方法之后,模型更新会话。因此,唯一一个同时包含在 Session 和 Model 中的相同属性可以具有不同值的情况是,在控制器方法中。非常感谢。【参考方案3】:

Java 方法参数是按值传递的。您可以在方法内为这个参数分配任何您想要的东西,但在它之外不会有任何效果。 Insisde 您正在处理参数副本的方法

【讨论】:

以上是关于Spring MVC - HttpSession.setAttribute 和 model.addObject 之间的区别的主要内容,如果未能解决你的问题,请参考以下文章

spring mvc怎么重定向

如何在 Spring MVC 中存储会话

技术Spring MVC 中获取session的几种方法

理解Spring MVC Model Attribute 和 Session Attribute

理解Spring MVC Model Attribute和Session Attribute

如何使用 Spring 将 HttpSession 放入 Aspect 类中?