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.
Related
I have some validation logic, which is based a user's session.
Сan I access the session from a class inherited from AbstractValidator?
Or is there another way to check RequestDTO based session?
For example I can use filters for that (and I can access the session via IRequest parameter req in overrided Execute method), but I don't know how to return the response from the class of the filter, bypassing the main method of the operation. If I will throw the Exception, the service will not work properly because RequestDTO declared outside of my project and it is not inherited from IReturn<> and does not contain a ResponseStatus field.
Thanks in advance for any help (and sorry for my English)
If your validator implements IRequiresRequest then it will injected with the current IRequest which you can use in your lambda expressions, e.g:
public class CustomValidator : AbstractValidator<Request>, IRequiresRequest
{
public IRequest Request { get; set; }
...
}
I'm using the Wicket Auth/Roles and I ran into the same problem as the OP of this thread.
I need to access the DB service layer in the AuthenticatedWebSession (for user authentication). I followed Steve Flasby's suggestion and did the following:
#Override
public Session newSession(Request request, Response response) {
Session s = new MySession(request);
mInjector.inject(s);
return s;
}
Unfortunately this results in
java.lang.IllegalStateException: EntityManager is closed
(presumably due to the fact that (a) I'm using open session in view, and (b) the session spans over several requests).
I solved this by moving the injection into the AuthenticatedWebSession.authenticate method.
#Override
public boolean authenticate(String username, String pass) {
Injector.get().inject(this);
...
}
I suspect that this is not best practice, because now I need to access to the service layer in other methods too, and it doesn't seem like a good idea to add Injector.get().inject(this) in each such method.
My question:
How do I perform injection into the session object upon each request? (Or, if this is a bad approach all together, how do I access the service layer in the AuthenticatedWebSession?)
You can implement IRequestCycleListener (extend AbstractRequestCycleListener) and implement:
#Override
public void onBeginRequest(RequestCycle cycle)
{
if (Session.exists()) {
Injector.get().inject(Session.get());
}
}
Register your IRequestCycleListener in Application#init() with getRequestCycleListeners().add(new YourRequestCycleListener()).
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...
I have previously written Spring MVC web applications where there is a front controller and we have a request mapping in each of the methods and this method in turn invokes a service implementation finally returning a view to the UI. Now when I design JSF applications am not able to understand the flow as such -
This is what I currently have in my application:
The initial index.html redirects to the login page.
A backing bean for the login page which populates label values. Since it is an input form there is no other logic involved.
Once the user clicks on submit -> in the action method I have logic which will invoke the service(No.1) for authentication process and redirect the user to the home page by returning the name of the page
The home page displays various fields which are bound to a backing bean whose fields have to be populated by another web service call(No.2).
It is between the steps (3) and (4), I have a confusion. Previously in Spring I had an explicit mapping and I can "actually" control the logic in the front controller method. In JSF, I dont know whether the logic for No.2 web service call should be combined along with authentication call since I dont have a method to populate the beans.
It is as if I dont have the explicit control over the flow. I have read many articles trying to understand this but not am able to understand. Please provide me pointers and also some references which will actually explain this better.
Why can't you control the logic in JSF bean?Example usage with EJB
#ManagedBean
#RequestScoped
public class LoginBean {
#EJB
private AuthBean authBean;
#EJB
private UserSettings settingsBean;
private String name, password;
#PostConstruct
private void init() {
//do your initialization here
}
public String loginAction() {
User user = authBean.authenticate(user, password);
if(user != null) {
UserSetting settings = settingsBean.getSettings(user.getId());
return "home";
}
}
//setters and getters
}
In Spring MVC, suppose I define a SessionAttribute, using the #SessionAttribute tag like so:
#SessionAttributes(value = "myModel")
public class MyController{
...
}
Suppose that I forget to call status.setComplete() on the SessionStatus like so:
#RequestMapping(method = RequestMethod.POST)
public void doSomething(#ModelAttribute("myModel") MyModel model, SessionStatus status){
...
//status.setComplete(); <-- Never gets called
}
Will the model stay in the session forever? Will it ever get cleaned out, or will the session keep growing larger and larger as the user navigates the site?
There is a big debate on whether the session attributes are cleared after controller exit.
To clarify once and for all, we can look at the Spring MVC 3.1.0 RELEASE source code.
The interface org.springframework.web.bind.support.SessionAttributeStore exposes the following methods:
void storeAttribute(WebRequest request, String attributeName, Object attributeValue);
Object retrieveAttribute(WebRequest request, String attributeName);
void cleanupAttribute(WebRequest request, String attributeName);
The default implementation is org.springframework.web.bind.support.DefaultSessionAttributeStore
By doing a "Open Call Hierarchy" on cleanupAttribute() in Eclipse, we can see that the method is called by 2 different flows:
1) org.springframework.web.method.annotation.ModelFactory
public void updateModel(NativeWebRequest request, ModelAndViewContainer mavContainer) throws Exception {
if (mavContainer.getSessionStatus().isComplete()){
this.sessionAttributesHandler.cleanupAttributes(request);
}
else {
this.sessionAttributesHandler.storeAttributes(request, mavContainer.getModel());
}
if (!mavContainer.isRequestHandled()) {
updateBindingResult(request, mavContainer.getModel());
}
}
2) org.springframework.web.bind.annotation.support.HandlerMethodInvoker
public final void updateModelAttributes(Object handler, Map<String, Object> mavModel,
ExtendedModelMap implicitModel, NativeWebRequest webRequest) throws Exception {
if (this.methodResolver.hasSessionAttributes() && this.sessionStatus.isComplete()) {
for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {
this.sessionAttributeStore.cleanupAttribute(webRequest, attrName);
}
}
...
}
It is clear that in both cases, the session attribute is removed only when this.sessionStatus.isComplete() is called.
I dug into the code of DefaultSessionAttributeStore. Under the hood, it gets the real HTTP Session object to store attributes, so they can potentially be accessed by other controllers in the same session.
So no, the session attributes are not removed after a clean POST.
EDIT #2: Note that this answer is no longer correct. See #doanduyhai's answer below.
EDIT: Please note that this is for Spring 2.5 and may, but does not necessarily ensure that the same is for Spring 3.x. Double check the docs!
This is along the lines of what #Gandalf said.
Form controllers model a form request lifespan, from initial viewing of the form through form submission. After the form is submitted, the form controller's job is done, and it will remove the command object from the session.
So, to keep the command object in the session between form workflows you will need to manage the session manually. After a clean POST, the object is removed from session.
In short, I believe the setComplete() method is just good practice but is not necessarily required.
EDIT: I just looked in my Spring book to confirm this. I'll quote it:
When #SessionAttribute is not used, a
new command object will be created on
each request, even when rendering the
form again due to binding errors. If
this annotation is enabled, the
command object will be stored in the
session for subsequent uses, until
the form completes successfully. Then
this command object will be cleared
from the session. This is usually
used when the command object is a
persistent object that needs to be
identical across different requests
for tracking changes.
Essentially that's what I was saying above. It stores it in the session until you either A) call setComplete() or B) the controller successfully completes a POST.
Is there some reason why you would want to do that?
from this thread : #SessionAttribute Problem
The #SessionAttributes works in the same way as the sessionForm of the SimpleFormController. It puts the command (or for the #SessionAttributes any object) in the session for the duration between the first and the last request (most of the time the initial GET and the final POST). After that the stuff is removed.