Spring MVC - разлика между HttpSession.setAttribute и model.addObject

Наскоро се опитвам да науча 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. Актуализираният обект shoppingCart обаче може да се види актуализиран, въпреки че не презаписвам обекта на сесията (тъй като обектът е същият обект, който вече е в сесия).

Но защо броят не се актуализира, въпреки че го презаписвам с session.setAttribute? Когато добавя новия обект за броене към модела (model.addObject("count", count)), тогава мога да видя актуализираната стойност на count. Но защо session.setAttribute не дава същия резултат?


person akcasoy    schedule 05.05.2013    source източник


Отговори (3)


Първо, @SessionAttribute не трябва да използва http сесията. Той използва SessionAttributeStore, който може да има всичко като резервно хранилище. Само изпълнението по подразбиране използва http сесията.

Причината, поради която вашият код не работи според очакванията, се крие в това как работи @SessionAttribute.

Преди да бъде извикан метод на контролер, всичко изброено в @SessionAttributes, във вашия случай {"warenkorb", "count"}, се чете от сесията и се добавя към модела.

След като методът се върне сесията се актуализира с всичко, което е добавено към модела в рамките на метода.

.addObject("count", count)

-> count се добавя към модела и след това към сесията.

session.setAttribute("count", count)

-> броят се добавя към сесията, но не и към модела. Той ще бъде добавен към модела преди следващото извикване на метод на контролер. Но засега моделът все още е със стария count. И моделът е това, което се добавя към заявката. И ако атрибут може да бъде намерен в обхвата на заявката, тогава jsp не се интересува какво има в сесията.

Когато използвате @SessionAttributesи @ModelAttribute (или Spring MVC като цяло), избягвайте използването на HttpSession или HttpRequest. Дори HttpResponseе с ограничена употреба. Вместо това прегърнете красотата на Spring MVC :)

person a better oliver    schedule 05.05.2013
comment
Така че основно; преди да бъде извикан метод на контролер, сесията актуализира модела. След метода моделът актуализира сесията. Така че единственият момент, когато един и същ атрибут, който се съдържа както в сесията, така и в модела, може да има различни стойности, е в метода на контролера. Благодаря ти много. - person akcasoy; 06.05.2013

model.addObject поставя обект в обхвата на заявката, докато HTTPsession.setAttribute го поставя в обхвата на сесията. И тъй като променливите в jsp се разрешават в следващия ред: обхват на страница -> обхват на заявка -> обхват на сесия -> обхват на приложение, получавате това, което получавате.

person Patison    schedule 05.05.2013
comment
Но аз дефинирах и двата атрибута като атрибути на сесия по-горе с @SessionAttributes({warenkorb, count}). Когато презапиша атрибута count с session.setAttribute(count, count), не трябва ли да променя атрибута с обхвата на сесията? може би не трябваше да пиша въпроса като разликата между setAttribute и addObject, а разликата между 2 обекта на сесията, използвани в метода deleteFromBasket, които и двата водят до различни начини (warenkorb е актуализиран, count все още е старият обект за броене). - person akcasoy; 05.05.2013
comment
Фух, най-накрая го реших.. променете сигнатурата на метода си на public ModelAndView deleteFromBasket(@PathVariable Integer position, @ModelAttribute("warenkorb") List<Item> warenkorb, @ModelAttribute("count") Integer count, ModelMap modelMap) и за да зададете атрибут в сесията, направете: modelMap.addAttribute("count", --count); - person Patison; 06.05.2013
comment
Когато променя подписа на метода, докато пишете, той работи, знам :) моят метод addToBasket работи по същия начин.. Просто се опитвах да разбера общата концепция, опитвайки се да използвам различни неща като HttpSession и т.н. Въпреки това много ви благодаря. - person akcasoy; 06.05.2013

Параметрите на Java метода се предават чрез стойности. Можете да присвоите на този параметър всичко, което искате вътре в метода, но това няма да има никакъв ефект извън него. Вътре в метода, с който работите с копието на param

person Radek    schedule 14.09.2014