From the reference link: How do you redirect to another URI and access an object from the previous modelAndView, if the public ModelAndView sendEmail() {} had been modified and say, other objects like Collection or HashMap would have added in the Model Object, then how would you have accessed in the /nextPageclass method ?
If possible I would just stick it into the HttpSession object:
public ModelAndView something(HttpServletRequest request) {
HttpSession session = request.getSession();
session.setAttribute("name", "object");
return new ModelAndView(new RedirectView("nextPageclass"));
}
This should make the values available during the entire user's sessions rather than just on the individual page request. You will end up having to manage the state of Session attributes but this provides a way to make the data available on the next page or any page thereafter without having to consistent get() and set() the value.
Related
I am trying to understand how to sending HttpSession as a parameter in the spring controller works.
I have a jsp which does a post request on clicking the submit button. In the controller, reading the sessions as follows
In the controller:
public ModelAndView viewEditFundClass(HttpServletRequest request,HttpServletResponse response,Model model){
HttpSession session = (HttpSession)request.getSession();
java.util.Date startDate = sesseion.getAttribute("startDate");
However, when I just change the controller to the following, I am still able to access the session
public ModelAndView viewEditFundClass(HttpServletRequest request,HttpServletResponse response, HttpSession session,Model model)
I would like to know how this is done in Spring, ie how did the post request pass the HttpSession as a parameter? will this session be valid?
Assuming you're using Spring 3+ #Controller and #RequestMapping handler methods, Spring defines a default set of supported argument types for your handlers
Session object (Servlet API): of type HttpSession. An argument of
this type enforces the presence of a corresponding session. As a
consequence, such an argument is never null.
Spring uses the strategy pattern to accomplish this, using the interface HandlerMethodArgumentResolver. It checks the parameter types of your handler methods and, for each type, tries to find a HandlerMethodArgumentResolver that will be able to resolve an argument for it.
For HttpSession, that implementation is ServletRequestMethodArgumentResolver.
My objective is to pass model attributes from controller to JSP page during a redirect and avoid the attribute being displayed in URL. The source code below is validating login from datastore using java data objects.
Controller:
#Controller
public class LoginController {
int count;
PersistenceManager pm = PMF.get().getPersistenceManager();
//Instance of data class
User user;
ModelAndView modelAndView=new ModelAndView();
#RequestMapping(value="/Login",method = RequestMethod.POST)
public ModelAndView loginValidate(HttpServletRequest req){
//Getting login values
String uname=req.getParameter("nameLogin");
String pswd1=req.getParameter("pswdLogin");
count=0;
user=new User();
//Generating Query
Query q = pm.newQuery(User.class);
q.setFilter("userName == userNameParam");
q.declareParameters("String userNameParam");
try{
List<User> results = (List<User>) q.execute(uname);
for (User u: results) {
String userName=u.getUserName();
if(userName.equals(uname)){
System.out.println(u.getPassword());
if(u.getPassword().equals(pswd1)){
count=count+1;
modelAndView.setViewName("redirect:welcome");
modelAndView.addObject("USERNAME",uname);
return modelAndView;
}
//rest of the logic
}
JSP:
<h1>Welcome ${USERNAME} </h1>
My current URL is /welcome?USERNAME=robin
My goal is to display it as /welcome
Also, my page is supposed to display "Welcome robin" whereas it displays only Welcome.
RedirectAttributes only work with RedirectView, please follow the same
#RequestMapping(value="/Login",method = RequestMethod.POST)
public RedirectView loginValidate(HttpServletRequest req, RedirectAttributes redir){
...
redirectView= new RedirectView("/foo",true);
redir.addFlashAttribute("USERNAME",uname);
return redirectView;
}
Those flash attributes are passed via the session (and are destroyed immediately after being used - see Spring Reference Manual for details). This has two interests :
they are not visible in URL
you are not restricted to String, but may pass arbitrary objects.
You need to be careful here because I think what are you trying to do is not supported for a good reason. The "redirect" directive will issue a GET request to your controller. The GET request should only retrieve existing state using request parameters, this is the method contract. That GET request should not rely on a previous interaction or on any object stored some where in the session as a result of it. GET request is designed to retrieve existing (persisted) state. Your original (POST) request should have persisted everything you need for you GET request to retrieve a state.
RedirectAttributes are not designed to support you in this case, and even if you managed to correctly use it it will only work once and then they will be destroyed. If you then refresh the browser you will get an application error because it cannot find your attributes anymore.
Assuming i dont have any 'password protected' pages, but sometimes need to know which user clicked some jsf-button, is the below okay, or should I also use HttpServletRequest.login()
some managed bean that handles logins:
public void login(String name, String password) {
try {
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
MyUser user = userEjb.login(name, password);
request.getSession().setAttribute("user", user);
} catch {
//login failed message..
}
}
method invoked by h:commandButton:
public void doSomething() {
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
MyUser user = request.getSession().getAttribute("user");
//Is the user object 'safe' here?
}
There is nothing wrong with the idea, assuming your login operation is called at login time and the other snippet is on button press, but I would be careful about what is put in the session.
For example, if the password is persisted in your MyUser class, you wouldn't want that stored in the session. The reason why? It is possible to browse sessions from the server, thus the unencrypted password would be visible to a malicous/nosey person with access to your system.
Also what happens if someone accidentally dumps the user object to a web page, or it leaks in an error?
So, given the above paranoia based monologue, my recommendation would be to store a view bean equivalent to your MyUser object, which only contains minimal fields, (username, name) for use in your application, e.g., last modified by fields, etc.
I think the original question was confusing.
I have a HashMap that needs to be a Collection from a database that I'd like to send to a view via a Spring Controller. I don't want to put this HashMap in the model.addAttribute() because the Spring Model object returns a Map and my JSP needs the collection to be a Collection<Object>. If I set my HashMap.values() in a request.setAttribute, how do I go about dispatching that request variable to the view if my method is returning a String?
#RequestMapping(method = RequestMethod.GET)
public String home(Locale locale, Model model, HttpServletRequest request) {
model.addAttribute("surveys", mySurveys); //this is a map and I need a Collection<Object>
//So I'd like to do this, but how do I get to the "evaluations" object in a view if I'm not dispatching it (like below)??
request.setAttribute("evaluations", mySurveys);
//RequestDispatcher rd = request.getRequestDispatcher("pathToResource");
//rd.forward(request, response);
return "home";
}
EDIT: The Spring Tag library cannot be used for this particular usecase.
Thanks.
If mySurveys is a Map, then perhaps you can put mySurveys.values() into the ModelMap instead of mySurveys (Also, are you intending to use a ModelMap instead of a Model?)
In the code below, surveys would be a Collection of Objects and would be accessible in the jsp via ${surveys}
#RequestMapping(method = RequestMethod.GET)
public String home(ModelMap modelMap, HttpServletRequest request) {
Map<String,Object> mySurveys = getMySurveys();
modelMap.addAttribute("surveys", mySurveys.values());
return "home";
}
I think you're confused as to what ModelMap is.
You can annotate whatever variable you want to access in the view by #ModelAttribute and Spring will automatically instantiate it, and add it to the ModelMap. In the view, you can use it like:
<form:form modelattribute="myAttribute">
<form:input path="fieldInAttribute">
</form:form>
Hope this answers your question
Using spring MVC, I need to store my object into session and I should use the same object in several jsp pages using jstl. I have tried like this:
ModelAndView modelAndView = new ModelAndView("admin/addproduct", "category", categorynameList);
But I can't access the category to other jsp pages except addproduct page.
How can I do that?
Spring MVC provides more than one mechanisms that hide the plain use of HttpSession from you.
Have a look at the #SessionAttributes annotation, which allows you to define the attributes that will be stored in the session by your controller; this mechanism is mainly intended to maintain the conversational state for your handler and that state is usually cleared once the conversation is complete.
Also, you can define your bean as session scoped in the application context and then make use of a ScopedProxyFactoryBean (by simply adding an <aop:scoped-proxy/> element in your bean definition), thus being able to inject that bean in your singleton controllers.
You can pass the session directly to any annotated controller method:
#RequestMapping("somePathName")
public String someHandler(HttpSession session) {
session.setAttribute(...
The annotation #SessionAttributes is used on class level. Typically it's used on the #Controller class. It's 'value' element is of type String[] whose values are the matching names used in #ModelAttribute either on method level or on handler's method parameter level.
Let's consider following arrangement:
#Controller
#SessionAttributes("visitor")
#RequestMapping("/trades")
public class TradeController {
#ModelAttribute("visitor")
public Visitor getVisitor (....) {
return new Visitor(....);
}
....
}
In above code, when a request comes in, the first thing Spring will do is to notice #SessionAttributes('visitor') and then attempt to find the value of 'visitor' in javax.servlet.http.HttpSession. If it doesn't find the value, then the method with #ModelAttribute having the same name 'visitor' (method getVisitor()) will be invoked. The returned value from such method will be used to populate the session with name 'visitor'.
Now that 'visitor' with it's value is already in HttpSession, let's consider following arrangement:
#Controller
#SessionAttributes("visitor")
#RequestMapping("/trades")
public class TradeController {
#RequestMapping("/**")
public String handleRequestById (#ModelAttribute("visitor") Visitor visitor,
Model model,
HttpServletRequest request) {
model.addAttribute("msg", "trades request, serving page " +
request.getRequestURI());
visitor.addPageVisited(request.getRequestURI());
return "traders-page";
}
.......
}
On finding #ModelAttribute("visitor") in the target handler method, Spring will retrieve the value of 'visitor' from the session and will assign the value to the Visitor parameter and will invoke the method. At this step, Spring doesn't care how the session was populated with 'visitor', Whether it was populated using the last arrangement or some other way, it doesn't matter, Spring only requires the annotation #SessionAttributes('visitor'), the handler method parameter with #ModelAttribute("visitor") and the value of 'visitor' in HttpSession. If spring can't find it in the session and last arrangement is not available then following exception will be thrown:
org.springframework.web.HttpSessionRequiredException: Expected session attribute 'visitor'
In other words: when the target handler method is invoked first time in a given session, then method with #ModelAttribute('visitor) is invoked, the returned value is populated in HttpSession and the handler method with the same value is invoked. For the subsequent requests within the same HTTPSession, Spring retrieves the same object from the session and doesn't call the method with #ModelAttribute('visitor') again till the end of the session
Following is the complete controller class:
#Controller
#SessionAttributes("visitor")
#RequestMapping("/trades")
public class TradeController {
#RequestMapping("/**")
public String handleRequestById (#ModelAttribute("visitor") Visitor visitor,
Model model,
HttpServletRequest request) {
model.addAttribute("msg", "trades request, serving page " +
request.getRequestURI());
visitor.addPageVisited(request.getRequestURI());
return "traders-page";
}
#ModelAttribute("visitor")
public Visitor getVisitor (HttpServletRequest request) {
return new Visitor(request.getRemoteAddr());
}
}
In above example we are tracking the user visited pages within the same HTTP session. We are using the wildcard '/**' so that all request starting with 'trades' will map to this controller.
Inject session to your controller classes, store your object there and use it when you need it, e.g.:
#Controller
public class SomeController {
//#Autowired
//private HttpSession session; This is not desired. See the discussion in the
//comments.
#RequestMapping("somePathName")
public String someHandler(HttpSession session) { //Session will be injected by
//Spring without any additional annotations.
//...
session.setAttribute("category", yourObject);
}
}
If you need to access category on other pages than admin/addproduct you will need to add it to respective models as follows:
#RequestMapping("somePathName")
public String someHandler(Model model) {
//...
model.addAttribute("category", yourObject);
//...
return "yourPageName";
}
Update: according to ALex's comment that injecting HttpSession instance into field is strongly not desired due to thread safety concerns I've changed the source respectively.