Announcement Announcement Module
Collapse
No announcement yet.
Problem with @SessionAttributes and @ModelAttribute Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Problem with @SessionAttributes and @ModelAttribute

    I have a create account controller:

    Code:
    @Controller
    @SessionAttributes(CreateAccountController.MODEL_ATTRIBUTE)
    public class CreateAccountController {
    and I have a a method on that controller:

    Code:
    @RequestMapping(value=URL_CREATE_ACCOUNT, method=RequestMethod.GET)
    public String createAccount(@ModelAttribute(MODEL_ATTRIBUTE) CreateAccount createAccount, Map<String,Object> map, SessionStatus sessionStatus) {
    However when I attempt to access this url, I get the following exception:
    Code:
    org.springframework.web.HttpSessionRequiredException: No session found - session required for attribute 'createAccount'
    How do I force a session to be made?

  • #2
    i think with:

    <property type session=true />

    something like that. google it

    Comment


    • #3
      Even if that were valid XML, it wouldn't matter. I'm using annotations, which mean my controllers are not the old school spring controller like you're thinking, they are just regular classes.

      Comment


      • #4
        Bump ... anyone?

        Comment


        • #5
          I'm having a simliar problem right now.

          I'm getting the error right after a "redirect:/some/url" if that helps.

          Comment


          • #6
            can you post your whole controller code?

            In order to use the sessionAttribute you still have to create/resolve it somehow. It's easy to see how it's done when looking at the PetClinic sample.

            Code:
            package org.springframework.samples.petclinic.web;
            
            import [...] (removed by me to save space)
            /**
             * JavaBean Form controller that is used to edit an existing <code>Pet</code>.
             *
             * @author Juergen Hoeller
             * @author Ken Krebs
             */
            @Controller
            @RequestMapping("/editPet.do")
            @SessionAttributes("pet")
            public class EditPetForm {
            
            	private final Clinic clinic;
            
            	@Autowired
            	public EditPetForm(Clinic clinic) {
            		this.clinic = clinic;
            	}
            
            	@ModelAttribute("types")
            	public Collection<PetType> populatePetTypes() {
            		return this.clinic.getPetTypes();
            	}
            
            	@RequestMapping(method = RequestMethod.GET)
            	public String setupForm(@RequestParam("petId") int petId, Model model) {
            		Pet pet = this.clinic.loadPet(petId);
            		model.addAttribute("pet", pet);
            		return "petForm";
            	}
            
            	@RequestMapping(method = RequestMethod.POST)
            	public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result, SessionStatus status) {
            		new PetValidator().validate(pet, result);
            		if (result.hasErrors()) {
            			return "petForm";
            		}
            		else {
            			this.clinic.storePet(pet);
            			status.setComplete();
            			return "redirect:owner.do?ownerId=" + pet.getOwner().getId();
            		}
            	}
            
            }

            Comment


            • #7
              While I can't speak for Eric, I've got something similar to this:

              Code:
              @Controller
              @RequestMapping("/home")
              @SessionAttributes("account")
              public class AccountHome {
              	
              	@RequestMapping(method = RequestMethod.GET)
              	public String handleHome(@ModelAttribute("account") Account account) {
              		// do some stuff
                              return "home.jsp";
              	}
              
              }
              And this throws rg.springframework.web.HttpSessionRequiredExceptio n: No session found - session required for attribute 'account'

              I really don't understand how sessions are handled w/ Annotations. The reference documentation is like

              it's as easy as this: @SessionAttributes("something")

              but that doesn't give me much insight

              Comment


              • #8
                My problem is I want to store items in the session but I don't want them to be required, but from the looks of things, I would have to put placeholder data in the session to make this work, which seems pointless to me.

                Comment


                • #9
                  Why would you be trying to access a session form object on the Request/GET side of the transaction?

                  The way I understand @SessionAttributes in conjunction with @ModelAttribute is that you create the actual attribute on the GET side of things (by putting it in your ModelMap) and then retrieving it on the POST side.

                  Are you using @SessionAttributes like you would by using HttpSession.setAttribute() ? Because that's not what @SessionAttributes does.

                  Comment


                  • #10
                    If you do:

                    sessionStatus.setComplete() then @SessionAttributes() will be cleaned up.

                    See my next post for the URL (wouldn't let me put it in this one because this is my first post)

                    Comment


                    • #11
                      SessionStatus JavaDoc:

                      http://static.springframework.org/sp...#setComplete()

                      Comment


                      • #12
                        I don't have any trouble getting my session functionality to work via annotations, so long as I first prepare the form via a GET method, set an empty object into the session, and then return a view which renders the form. That will create a session so that the POST request will find it. However, I find it very limiting that I must create an object in the session before processing any POST request.

                        In my case, I'm working up a simple login page. At the time the form is rendered, I've got to create a totally empty User object to render the form. That's fine, but I see no reason to stick an empty object in the session, particularly since that empty object will then get broadcast to other containers in the cluster. I'd much rather have a mechanism by which I can instantiate a new form backing object when POST processing first begins, before binding and validation occur.

                        I believe this can be done as follows (this is untested, as I am still writing code and haven't tested):

                        @ModelAttribute("user")
                        public User instantiateEmptyUser() {
                        return new UserImpl();
                        }

                        @RequestMapping(method = RequestMethod.POST)
                        public String processSubmit(@ModelAttribute("user") User user, BindingResult result, SessionStatus status) {
                        // lookup user here
                        return "success";
                        }

                        This eliminates the requirement of placing an empty User object in the Session purely so that it exists for the subsequent post request, since the @ModelAttribute annotation on the method will cause that mathod to be executed before any processing occurs.

                        I'll report back if it turns out to work

                        --sam

                        Comment


                        • #13
                          Indeed, it works like a charm.

                          Code:
                          @Controller
                          @RequestMapping("/login.html")
                          public class LoginController {
                              private static Log log = LogFactory.getLog(LoginController.class);
                          
                              private ServiceFacade service;
                              
                              @Autowired
                              public LoginController(ServiceFacade service) {
                                  this.service = service;
                              }
                              
                              @InitBinder
                              public void setAllowedFields(WebDataBinder dataBinder) {
                                  dataBinder.setAllowedFields(new String[] {"username", "password"});
                              }
                              
                              @ModelAttribute("user")
                              public User populateUser() {
                                  log.debug("creating empty user");
                                  return new UserImpl();
                              }
                              
                              @RequestMapping(method = RequestMethod.GET)
                              public String setupForm(Model model) {
                                  log.debug("processing login GET method");
                                  return "login";
                              }
                          
                              @RequestMapping(method = RequestMethod.POST)
                              public ModelAndView processSubmit(@ModelAttribute("user") User user, 
                                                                BindingResult result, 
                                                                Model model,
                                                                HttpSession session) {
                                  log.debug("processing POST request");
                                  new LoginValidator().validate(user, result);
                                  if (result.hasErrors()) {
                                      log.debug("failed validation");
                                      return new ModelAndView("login", model.asMap());
                                  } else {
                                      log.debug("authorizing");
                                      User authUser = service.loadUserByCredentials(user.getUsername(), user.getPassword());
                                      if (authUser == null) {
                                          log.debug("failed authorization");
                                          model.addAttribute("authError", "Unable to authenticate " + user.getUsername());
                                          return new ModelAndView("login", model.asMap());
                                      }
                                      log.debug("success!");
                                      session.setAttribute("authUser");
                                      return new ModelAndView("welcome", "user", user);
                                  }
                              }
                          NOTE: The BindingResult parameter must immediately follow the ModelAttribute object that it is binding to. I'm not sure if you can have multiple ModelAttributes and multiple BindingResults by virtue of their placement next to each other, but that strikes me as the only reason for requiring this. If they are not placed next to each other in the parameter list, spring throws an exception at runtime.

                          Comment


                          • #14
                            Can be there more ModelAttributes?

                            Comment


                            • #15
                              So far as I am aware, there can be as many model attributes as you like. You can cause them to be added to the model by annotating a method that returns the object with the ModelAttribute annotation or by declaring an object to be a SessionAttribute and then setting it manually as part of the model (I guess it will be automagically added to the session as well) and then declaring a ModelAttribute parameter on your RequestMapping method, in which case the object will be pulled from the session and used as a ModelAttribute. See the example in the PetClinic sample, which is quoted in an earlier post on this thread

                              Comment

                              Working...
                              X