Spring MVC - difference between HttpSession.setAttribute and model.addObject
Asked Answered
E

3

6

I am trying to learn Spring MVC recently. It seems that i did not understand well the functionalities of @ModelAttribute annotation and 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 and count are the session attributes.

The problem is in the deleteFromCart method. I get the count from session, reassign it and overwrite it in session. But i cant see the updated value of count on jsp. However, the updated shoppingCart object can be seen updated, although i do not overwrite the session object (since the object is the same object which is already in session).

But why is the count not updated, although i overwrite it with session.setAttribute? When i add the new count object to the model (model.addObject("count", count)) then i can see the updated value of count. But why does not session.setAttribute give the same result?

Ecklund answered 5/5, 2013 at 10:9 Comment(0)
W
13

First of all, @SessionAttribute does not have to use the http session. It uses a SessionAttributeStore which can have anything as its backing storage. Only the default implementation uses the http session.

The reason why your code does not work as expected lies in how @SessionAttribute works.

Before a controller method is invoked, everything listed in @SessionAttributes, in your case {"warenkorb", "count"}, is read from the session and added to the model.

After the method has returned the session is updated with everything that has been added to the model within the method.

.addObject("count", count)

-> count is added to the model and afterwards to the session.

session.setAttribute("count", count)

-> count is added to the session but not to the model. It will be added to the model before the next invocation of any controller method. But as for now the model still has the old count. And the model is what gets added to the request. And if an attribute can be found in the request scope then the jsp does not care about what's in the session.

When you use @SessionAttributesand @ModelAttribute (or Spring MVC in general) then avoid using HttpSession or HttpRequest. Even HttpResponseis of limited use. Embrace the beauty of Spring MVC instead :)

Whorled answered 5/5, 2013 at 20:35 Comment(1)
So basically; before a controller method is invoked, the session updates the model. After the method, the model updates the session. So the only moment, when the same attribute which is contained both in Session and Model can have different values is, in the controller method. Thank you very much.Ecklund
B
2

model.addObject puts object to the request scope while HTTPsession.setAttribute puts it to the session scope. And since variables on jsp are resolved on the next order: page scope -> request scope -> session scope -> application scope, you get what you get.

Boabdil answered 5/5, 2013 at 13:58 Comment(3)
But i have defined both attributes as session attributes above with @SessionAttributes({"warenkorb", "count"}). When i overwrite the attribute count with session.setAttribute("count", count), should not it change the attribute with the session scope? maybe i should not have written the question as "the difference between setAttribute and addObject", but the difference between 2 session objects used in the deleteFromBasket method, which both results in different ways (warenkorb is updated, count is still the old count object).Ecklund
Fuh, finally solved it.. change your method signature to public ModelAndView deleteFromBasket(@PathVariable Integer position, @ModelAttribute("warenkorb") List<Item> warenkorb, @ModelAttribute("count") Integer count, ModelMap modelMap) and to set attribute in session do: modelMap.addAttribute("count", --count);Boabdil
When i change the methode signature as you write, it works i know :) my addToBasket method works the same way.. I was just trying to understand the general concept, trying to use different things like HttpSession etc. Nevertheless thank you very much.Ecklund
S
0

Java method params are passed by values. You can assign to this paramateter anything yoou want inside the method, but it won't have ny effect outside of it . Insisde of the method you're dealing with the copy of the param

Selenite answered 14/9, 2014 at 4:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.