I am using session.setAttribute to store user object after login. In next controller, I have #SessionAttribute for the same user and #ModelAttribute for same object to be used in the method mapped to a RequestMapping. After login if I click any link in the user home page it give
HttpSessionRequiredException: Session attribute '' required - not found in session
I am not sure what I am doing wrong. I went through many article and question in this site as well but could find any solution. The user object which I am storing in session stores user's account details which are required in all the controller to get different information from DB. I using SessionAttribute is wrong should I use HttpSession instead in all the controller and get the object from session manually or there is a proper way to handle in spring 3.0. Please note that this user object is not backing any form just login, but contains many other details.
As help would be good.
Have a look at my (non-perfect) use of session data:
#Controller
#SessionAttributes("sharedData")
public class RegistrationFormController {
#Autowired
private SharedData sharedData; // bean with scope="session"
#RequestMapping(value = {"/registrationForm"}, method = RequestMethod.GET)
public ModelAndView newForm() {
final ModelAndView modelAndView = new ModelAndView("registrationForm");
modelAndView.addObject("registrationForm", new RegistrationForm());
// I want to render some data from this object in JSP:
modelAndView.addObject("sharedData", sharedData);
return modelAndView;
}
#RequestMapping(value = {"/registrationForm"}, method = RequestMethod.POST)
public String onRegistrationFormSubmitted(HttpServletRequest request,
#ModelAttribute("registrationForm") RegistrationForm registrationForm, BindingResult result) {
if (result.hasErrors()) {
return "registrationForm";
}
// Perform business logic, e.g. persist registration data
return "formSubmitted";
}
}
Related
Actually I've googled to see how we can pass data from one controller to another in Spring MVC and I found that using flash attributes do the job.
It consists on declaring one controller with RequestMapping=GET and an other with RequestMapping=POST. I have tested this code in my controller and it worked.
#RequestMapping(value ="/ajouter", method = RequestMethod.POST)
public String add(#ModelAttribute User user,final RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("user", user);
return "redirect:/account";
}
and the other:
#RequestMapping(value ="/account", method = RequestMethod.GET)
public String addAccount(#ModelAttribute("user") User user,#ModelAttribute Account account) {
System.out.println(user.getId());
return "account";
}
But I have another case: I have two JSPpages:
The first will add a user into the database. I want to recuperate the id of the user just inserted to set it as a foreign key for the account (after submitting the page for adding a user, a second page for adding an account appears).
I've tested this code:
This controller will insert a user into the database and recuperate the user which has been just inserted.
#RequestMapping(value ="/addUser", method = RequestMethod.POST)
public String add(#ModelAttribute User user,final RedirectAttributes redirectAttributes) {
this.userService.insertData(user);
redirectAttributes.addFlashAttribute("user", user);
return "redirect:/account";
}
and this controller will insert an account into the database, but can not recuperate the user id of the user just inserted.
#RequestMapping(value= "/ajouterCompte", method = RequestMethod.POST)
public String addCompte(#ModelAttribute("account") Account compte,#ModelAttribute("user") User user){
System.out.println(user.getId()); //this code shows 0
System.out.println(compte.getPwd());
String hashPassword = passwordEncoder.encode(compte.getPwd());
System.out.println(hashPassword);
compte.setPwd(hashPassword);
compte.setId(user.getId());
this.compteService.insertCompte(compte);
return "redirect:/users";
}
I guess that the problem is that the 2 controllers are declared with a method method = RequestMethod.POST when it should be one GET and an other POST. But in this case how can I recuperate the id of the user so that it could be inserted into the database?
When I declare the second controller with GET, the insertion of the database fails!
Need your help please :(
The object which are set as flash attributes are only available for the first request after those have been set. (As also explained in the reference guide).
Assuming that in your account controller you have a GET based method for /account pre-populate the Account with the information at that point.
public String account(#ModelAttribute("user") User user, Model model) {
Account account = new Account();
account.setId(user.getId());
model.addAttribute("account", account);
return "account";
}
Now you can either annotate your controller with #SessionAttribute("account") to have the Account stored in the session in between requests. If so then you have to modify your POST handling method to include a SessionStatus object and after storing call setComplete() on it.
public String addCompte(#ModelAttribute("account") Account compete, SessionStatus sessionStatus){
...
sessionStatus.setComplete();
return "redirect:/users";
}
Or store the pre-filled information in hidden form fields so that it gets passed along with the following request and the Account can be reconstructed.
<form:hidden path="id" />
In a Spring 4.2 webapp, I have a rights object in the session from which I can query whether the logged in user has access to a specific page. I can check the access rights from a controller and redirect to another page with a message. The problem is I have to repeat this for every request method in every controller.
I can move almost all the code to an interceptor but I have no access to RedirectAttributes from there, so I don't know how I could add the error message. Is there a way?
#Controller
#SessionAttributes("rights")
#RequestMapping("/f")
public class FController {
...
#RequestMapping(value="/edit/{id}", method=RequestMethod.GET)
public String edit(#PathVariable("id") int id,
#ModelAttribute("rights") UserRights rights,
RedirectAttributes redA, ModelMap model) throws SQLException {
if (!rights.canAccess("/f/edit")) {
redA.addFlashAttribute("errormessage", messages.getMessage("error.noright", null, Locale.getDefault()));
return "redirect:/f/list";
}
... // set up model
return "fEdit";
}
...
}
Yes you can! It is not as well integrated as what you get in controller methods, but you can get access to the output flash map in an interceptor. You can find references for that in the chapter on Using flash attributes in Spring Framework ReferenceManual. And thanks to the ModelAndViewDefiningException, you can still ask Spring to do the redirect and process the output flash map
You could just put something like this in an interceptor:
if (!rights.canAccess("/f/edit")) {
// get access to the output flash map
FlashMap redA = RequestContextUtils.getOutputFlashMap(HttpServletRequest request);
// add the redirect attributes
redA.put("errormessage", messages.getMessage("error.noright", null, Locale.getDefault()));
// prepare the redirection
ModelAndView redirMav = new ModelAndView("redirect:/f/list");
// ask the spring machinery to process the redirection
throw new ModelAndViewDefiningException(redirMav);
}
Now I have a login code like this,UserInfo is a form with username and password
#RequestMapping(value = "/login/loginCheck", method = RequestMethod.POST)
public Map<String, Object> loginCheck(UserInfo userInfo)
#RequestMapping(value = "/login/PageA", method = RequestMethod.POST)
public Map<String, Object> PageA(){
//maybe check the session
//if session expired ,then redirect to login page
}
After login, I should redirect page to Page A, and record the username in session, So in spring framework, Do I just configure it or get Session from request ?
Hope to be clear.
There are many ways, one is to simply inject HttpSession into your handler method
#RequestMapping(value = "/login/PageA", method = RequestMethod.POST)
public Map<String, Object> PageA(HttpSession httpSession){
//maybe check the session
//if session expired ,then redirect to login page
}
The getAttribute method of HttpSession will throw IllegalStateException if session is no longer valid, but I have a feeling Spring MVC will create a new session for you when that happen, so also check for non-existence (null value)
Also have a look at the usage of #SessionAttributes and #ModelAttribute annotation on Spring doc, and Spring Security framework
I am writing a wizard-like controller that handles the management of a single bean across multiple views. I use #SessionAttributes to store the bean, and SessionStatus.setComplete() to terminate the session in the final call. However, if the user abandons the wizard and goes to another part of the application, I need to force Spring to re-create the #ModelAttribute when they return. For example:
#Controller
#SessionAttributes("commandBean")
#RequestMapping(value = "/order")
public class OrderController
{
#RequestMapping("/*", method=RequestMethod.GET)
public String getCustomerForm(#ModelAttribute("commandBean") Order commandBean)
{
return "customerForm";
}
#RequestMapping("/*", method=RequestMethod.GET)
public String saveCustomer(#ModelAttribute("commandBean") Order commandBean, BindingResult result)
{
[ Save the customer data ];
return "redirect:payment";
}
#RequestMapping("/payment", method=RequestMethod.GET)
public String getPaymentForm(#ModelAttribute("commandBean") Order commandBean)
{
return "paymentForm";
}
#RequestMapping("/payment", method=RequestMethod.GET)
public String savePayment(#ModelAttribute("commandBean") Order commandBean, BindingResult result)
{
[ Save the payment data ];
return "redirect:confirmation";
}
#RequestMapping("/confirmation", method=RequestMethod.GET)
public String getConfirmationForm(#ModelAttribute("commandBean") Order commandBean)
{
return "confirmationForm";
}
#RequestMapping("/confirmation", method=RequestMethod.GET)
public String saveOrder(#ModelAttribute("commandBean") Order commandBean, BindingResult result, SessionStatus status)
{
[ Save the payment data ];
status.setComplete();
return "redirect:/order";
}
#ModelAttribute("commandBean")
public Order getOrder()
{
return new Order();
}
}
If a user makes a request to the application that would trigger the "getCustomerForm" method (i.e., http://mysite.com/order), and there's already a "commandBean" session attribute, then "getOrder" is not called. I need to make sure that a new Order object is created in this circumstance. Do I just have to repopulate it manually in getCustomerForm?
Thoughts? Please let me know if I'm not making myself clear.
Yes, sounds like you may have to repopulate it manually in getCustomerForm - if an attribute is part of the #SessionAttributes and present in the session, then like you said #ModelAttribute method is not called on it.
An alternative may be to define a new controller with only getCustomerForm method along with the #ModelAttribute method but without the #SessionAttributes on the type so that you can guarantee that #ModelAttribute method is called, and then continue with the existing #RequestMapped methods in the existing controller.
I am loading a user object my calling a service and then store this user as a command object in the model on GET in the controller. This user object has many properties that are not mapped in the jsp page. After submitting the form, I am getting the command object i the controller on POST. But strangely, I only see the properties in the command object which are mapped to the jsp page. All the other properties those were there when I load the object are lost. I need all the properties in object to be able to successfully save it in hte database.
Can anybody help me figure this problem? Thanks!
Update
I am adding some code to better understand it. In POST handler, I was expecting the command object to have all the properties that was loaded in GET handler in addition to the properties that are bound with jsp. Instead I am losing all propeties except those are bound to the jsp. Am I doing something wrong here?
#RequestMapping(method = RequestMethod.GET)
public String showForm(ModelMap model, HttpSession session, HttpServletRequest request) throws Exception {
UserBean user = Util.getUser(session);
UserBean command = (UserBean)userProfileService.loadByUserName(user.getUserName());
model.addAttribute("command", command);
return formView;
}
#RequestMapping(method = RequestMethod.POST)
public String onSubmit(#ModelAttribute("command") UserBean command, BindingResult result, HttpSession session) throws Exception {
UserBean user = (UserBean) command;
userProfileService.saveUser(user);
return "successView";
}
Update
I am adding some code to better understand it. In POST handler, I was expecting the command object to have all the properties that was loaded in GET handler in addition to the properties that are bound with jsp. Instead I am losing all propeties except those are bound to the jsp. Am I doing something wrong here?
#RequestMapping(method = RequestMethod.GET) public String showForm(ModelMap model, HttpSession session, HttpServletRequest request) throws Exception { UserBean user = Util.getUser(session); UserBean command = (UserBean)userProfileService.loadByUserName(user.getUserName()); model.addAttribute("command", command); return formView; }
#RequestMapping(method = RequestMethod.POST) public String onSubmit(#ModelAttribute("command") UserBean command, BindingResult result, HttpSession session) throws Exception { UserBean user = (UserBean) command; userProfileService.saveUser(user); return "successView"; }
Update
If I store the command object in session how would the jsp bind the propeties. I thought I needed to store it in model for that?
Could you explain please.
Update
storing the command object in session solves the problem. I was able to store it by using
#SessionAttributes ("command")
Thanks a lot!
That's expected behaviour. Spring does not take your existing object (how would it get it?) - it creates a new one and fills it with data.
You can use the #ModelAttribute annotated-method to specify a method which will load the existing object from storage (db?) by its ID (submitted).
#ModelAttribute annotated methods are executed before the chosen #RequestMapping annotated handler method. They effectively pre-populate the implicit model with specific attributes, often loaded from a database. Such an attribute can then already be accessed through #ModelAttribute annotated handler method parameters in the chosen handler method, potentially with binding and validation applied to it.
See 15.3.2.8 of the MVC docs
The Spring-MVC Model values become Request scope attributes in your JSP. This is a one way translation, Spring-MVC does not restore the Model values when the user POSTs a form from your page.
When I need to store information between a GET and a POST (that is, set something on a GET and read it back on a POST), I set a Session attribute.
In your case, I believe that you will need to do one of the following:
Call Util.getUser(session); in the onSubmit method.
Store the command object in the session in the showForm and retrieve it in the onSubmit method>
#ModelAttribute is used to direclty set the values in the Student object from the jsp, other wise in the servlet you have to get the properties using request.getattribute() and than call student setter method.
so u can use both the keywords in jsp page.
<form action="grade" method="get" name="contact1" modelAttribute="contact1">
</form>
or