I have the following problem with annotation based Spring MVC:
I have two Controllers (LoginController, AdminController) and I can pass an object (loggedInUser of type BonjourUser) form the LoginController to the AdminController by persisting it in the session. So far so good.
To prevent hotlinking, on the initial "GET" the AdminController verifies it received a valid admin-user when it is called.
This works fine the first Time, because the loginController added the object to the session.
Now here comes my problem:
Once the admin has logged in and tries to reaccess the admin-page (eg via a link in the JSP) the user-object seems to have vanished from the session, for I get a HttpSessionRequiredException for the "loggedInUser" attribute.
AFAIK the object should not be removed from the session unless I call setComplete() on the session. (I am not calling this method!) So why is the attribute removed from the session? I read here that you cannot pass session attribues between controllers. But then here it is said that it is possible. I also think it should work, since I already pass a parameter between controllers, when I redirect from the LoginController to the AdminController.
So here is the code:
LoginController:
#Controller
#SessionAttributes("loggedInUser")
public class LoginController extends BonjourController
{
[...]
#RequestMapping(value = {"/home"}, method = RequestMethod.POST)
public String validate(#ModelAttribute(value = "command") BonjourUser user, ModelMap map, HttpSession session)
{
[...]
map.addAttribute("loggedInUser", loggedInUser);
[...]
return "redirect:/admin";
}
}
And the AdminController:
#Controller
#RequestMapping(value = "/admin")
#SessionAttributes("loggedInUser")
public class AdminController extends BonjourController
{
#RequestMapping(method = RequestMethod.GET)
public String loginAdmin(#ModelAttribute("loggedInUser") BonjourUser loggedInUser, ModelMap map, HttpSession session)
{
//check if access is authorized
if(loggedInUser == null)
{
return "redirect:/login";
}
[...]
}
}
The link I use in the admins' jsp (which leads to the exception) looks like this
Once more to admin section
Basicaly I get the same exception when I just enter this in my browsers URL-bar:
http://localhost:8080/Bonjour/admin
The exception looks like this:
org.springframework.web.HttpSessionRequiredException: Expected session attribute 'loggedInUser'
So what do I need to change to ensure the user-object (loggedInUser) is not removed from the session?
Thanks in advance,
Maex
Update Spring to the latest version and it should work. See the comment to this answer: https://stackoverflow.com/a/9412890/1981720
I tried 3 different versions of spring now:
3.1.1
3.2.2
3.2.3
Always the same problem. The debugger tells me this:
I pass from login to admin:
object is perfectly stored in the session -> attributes map.
I use a link or re-type the url to access the same page again:
no object any more in session -> attributes map.
My bad - I blocked cookies!
So the session had no chance to be persisted except for POST requests, therefor the login worked but the GET for the same page did not...
Related
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);
}
I am trying to do a simple android application that communicates with a Spring server.
I'd like to use Sessions to store data of each logged in User.
My App exchange Json objects with the server and the Request Mapping is like this:
#Controller
public class LoginController {
#Autowired
private IUserDao userDao;
#RequestMapping( value = "/loginJson",method = RequestMethod.POST)
public #ResponseBody loginResponse login(#RequestBody loginModel login) {
loginResponse response=userDao.checkCredentials(login.getUsername(),login.getPassword());
System.out.println("Result="+response.isSuccess());
System.out.println("Received:"+login.getUsername()+" "+login.getPassword());
return response;
}
}
The controller is working fine, but I can't figure out how to store a sessione variable. I found many documents explaining Spring Sessions, but each of them different from the other.
Someone can suggest me some simple way to do this or some kind of good tutorial?
Not sure what you mean by saying Spring session, but you can declare additional HttpSession parameter in your method, and then do whatever you like inside of the method. Is this what you wanted to find out?
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";
}
}
I make (thanks with some users on this portal) my application that implements SessionAware.
This is my actual code :
public class UserManager extends ActionSupport implements SessionAware {
private Map<String, Object> session;
#Override
public String execute() throws Exception {
return SUCCESS;
}
public void setSession(Map<String, Object> map) {
this.session=map;
}
public String checkLogin() {
session.put("loggedOn", true);
return SUCCESS;
}
public String checkLogout() {
session.clear();
return SUCCESS;
}
}
And i check these variables on my .jsp :
<s:if test="#session['loggedOn']!=true">
DIV LOGIN
</s:if>
<s:else>
DIV LOGOUT
</s:else>
An easy piece of code.
What i'd like to know is this :
1 - the bean is (as default) request scoped. So when the request is finished it will be destroyed. But i see that, when i put a variable in the Map, it still alive on the server. How is possible? Is a variable of my Bean.
2 - Who call the setSession method? I think the servlet, due to the fact I implements that interface?
3 - I would like to detach about saving object/bean on a Session Object. I'd like to use the Bean session scoped (as for any kind of MVC framework). How can I do it on struts2?
Hope you can make clear these questions :) Cheers
1) Your bean is a struts2 action as such it is action scoped (which is a more restrictive scope than request). I say that action is a lesser scope because you can forward an action to another action in which case the previous action goes out of scope, request scoped objects however will stay in scope until the request is served. When you implement SessionAware you are provided with a reference to the SessionObject you are then putting your object into the Session object who's life span is much longer than your action. Clear your browser cache will remove the session value... you can also remove them by code be implementing SessionAware and removing the value from the map.
2 - The session already exists. You can get the session and add keys but even if you don't put anything in it, it will be there for use.
3 - You have a later question already for this topic see my answer there.
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