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<Item> 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)时,请避免使用HttpSession
或HttpRequest
。甚至HttpResponse
的用途也有限。拥抱Spring MVC
的美丽吧:)
【讨论】:
所以基本上;在调用控制器方法之前,会话会更新模型。在该方法之后,模型更新会话。因此,唯一一个同时包含在 Session 和 Model 中的相同属性可以具有不同值的情况是,在控制器方法中。非常感谢。【参考方案3】:Java 方法参数是按值传递的。您可以在方法内为这个参数分配任何您想要的东西,但在它之外不会有任何效果。 Insisde 您正在处理参数副本的方法
【讨论】:
以上是关于Spring MVC - HttpSession.setAttribute 和 model.addObject 之间的区别的主要内容,如果未能解决你的问题,请参考以下文章
理解Spring MVC Model Attribute 和 Session Attribute