Spring Framework Annotation @SessionAttributes can be confusing
I spent a fair amount of time banging my head against the wall trying to figure out how @SessionAttributes works in Spring’s annotations. The concept and implementation is fairly simple, the use and lack of documentation is confusing. Here’s your standard usage:
@Controller@RequestMapping("/someForm.do")
@SessionAttributes("fooForm")
public class FooFormController {
@RequestMapping(method = RequestMethod.GET)
public String setupForm(ModelMap model) {
FooForm fooForm = new FooForm();
// populate fooForm
model.addAttribute("fooForm", fooForm);
return "fooFormDisplayPage.jsp";
}
@RequestMapping(method = RequestMethod.POST)
public String processForm(@ModelAttribute("fooForm") FooForm fooForm) {
// do something with fooForm
status.setComplete();
return "redirect:/someOtherView";
}
}
The way this works is that the object that is inserted into the ModelMap and identified by @SessionAttributes is stored in the session across the life of the controller. The ModelMap object’s lifespan is tied directly to that of the controller object. Despite it’s name, @SessionAttributes has absolutely nothing to do with HttpSession.set/getAttribute(), it’s simply the annotated version of <sessionForm> from the xml version of the Spring configuration. The upshot of this is that the value identified in @SessionAttributes is not available to a different controller.
What if you want to store something in the session across multiple requests? The tried and true method of storing it in the HttpSession is still valid:
@RequestMapping(method = RequestMethod.POST);
public String processForm(@ModelAttribute("fooForm") FooForm fooForm,
HttpSession session) {
// do something with fooForm
session.setAttribute("fooForm", fooForm);
status.setComplete();
return "redirect:/someOtherView";
}
You can also define multiple request mappings inside of the same Controller object
@Controller
public class MultiViewController {
@RequestMapping("/foo");
public String handleFooRequest(ModelMap model) {
// Handle request
}
@RequestMapping("/bar");
public String handleBarRequest(ModelMap model) {
// Handle request
}
}
And there you go. Annotations are neat, allow for straight up pojos, and remove a lot of unnecessary XML configuration. Use them, just make sure they are adequately documented.