In the old AbstractFormController you had the option to keep the form object in session between subsequent POST requests but to be cleared (transparently) at the first GET request (using setSessionForm(true)).
The current @SessionAttributes annotation implies keeping the specified model attributes until you call SessionStatus.setComplete() and I find it difficult to simulate the old functionality.
You can not call setComplete() in the last POST request because you don't know if it's going to be the last, neither can you call it in GET requests because you want it cleared before your GET handler so the method that creates the model is called.
I can think of two workarounds but neither is a clean way of implementing this.
1: Call model attribute creator method yourself in GET:
The main problems with this approach are that you have to add every parameter createCommand needs to every GET method and you have to assume the implementation uses your myCommand (from modelMap) and not the one in session.Code:@SessionAttributes("myCommand") @RequestMapping("...") public class MyController { @ModelAttribute("myCommand") public MyCommand createCommand(@RequestParameter("...") someParam) { //create and return a new MyCommand object using someParam } @RequestMapping(method = RequestMethod.GET) public String show(ModelMap modelMap, @RequestParameter("...") someParam) { //just ignore the one in session, don't even add it as a @ModelAttribute parameter MyCommand myCommand = createCommand(someParam); modelMap.put("myCommand", myCommand); //use myCommand return "someView"; } }
2. complete the session and do a forward
The problems with this approach are that you have to add HttpSessionRequest to all GET methods and createCommand method and you have to add an attribute to the request like "createCommandWasCalled" in order to avoid recursion (you only forward the first time, when createCommand was not called because myCommand was in session).Code:@SessionAttributes("myCommand") @RequestMapping("...") public class MyController { @ModelAttribute("myCommand") public MyCommand createCommand(@RequestParameter("...") someParam, HttpSessionRequest request) { request.addAttribute("createCommandWasCalled", true); //create and return a new MyCommand object using someParam } @RequestMapping(method = RequestMethod.GET) public String show(@ModelAttribute("myCommand") MyCommand myCommand, SessionStatus sessionStatus, HttpSessionRequest request) { if (request.getAttribute("createCommandWasCalled") == null) { sessionStatus.setComplete(); return "forward:..."; } //use myCommand return "someView"; } }
Both approaches add code that is not straightforward. Is there a better way of doing this ?


Reply With Quote
