Spring MVC Controller misunderstanding - java

Code from a controller:
#Controller
public class HomeController {
#Autowired
private ItemService itemService;
#RequestMapping("/home")
public String showHomePage(Map<String, Object> model) {
model.put("items", itemService.getItems());
return "home";
}
}
And a part of the correspondent home.jsp:
<c:forEach items="${items}" var="item">
${item}
</c:forEach>
In a browser I get elements that are returned from itemService.getItems().
How Spring finds out that model map contains values to be request attributes?

Does the DispatcherServlet copy contents of all parameters of type Map to request attributes?
Yes, Spring MVC copies all the parameters from model to HttpServletRequest object. The reason why Spring people chosen not to use the HttpServeltRequest directly, is due to the requirement that they want to be as independent from the view technologies as possible, so being able to drive the view technologies that don't depend on the HttpServeltRequest
Exposing the model as request parameters is a facet of view, and you'll find the appropriate code if you check out the source of SpringMVC's InternalResourceView which extends from AbstractView that holds the exposeModelAsRequestAttributes method

Related

Spring MVC : how do I show data from DAO classes

I have a DAO java class that has a method called getTableFromDatabase(), it queries the MySQL and return resultTable, a hashmap of data. I want to use this hashmap and print the content in my jsp page using Spring MVC, how should I do this?
I know that I can use JSTL to print a table, my problem is how to pass this table from DAO to jsp page.
Thanks !
In spring mvc you have to return a ModelAndView class and this class will carry corresponding jsp file and parameters will be passed to jsp.
For example
In your controller request handler method you will return an instance of ModelAndView
#RequestMapping(...)
public ModelAndView handle(){
ModelAndView ret = new ModelAndView("view name");
ret.addAttribute("x","value");
}
in your jsp you can access to x via ${x} syntax.
Spring mvc document reference:
public ModelAndView addObject(Object attributeValue) Add an attribute
to the model using parameter name generation. Parameters:
attributeValue - the object to add to the model (never null) See Also:
ModelMap.addAttribute(Object), getModelMap()
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/ModelAndView.html

Unable to populate modelAttribute in spring

I am unable to get the ModelAttribute for second request.
My first request is initForm() method I prepared Command object and able to display the command in jsp.
Through initForm() I am populating command and that command I want in editForm when I will do ajax call.
Here is my spring form
<form:form method="POST" action="addstudentdetails.htm" commandName="command">
Ignore what is inside this
Name: Shoaib Age:23 edit
</form:form>
My ajax request:
function editStudentDetails(studentId,index){
$.ajax(
{url:"editstudentdetails.htm",
method:"GET",
data:{"action":"edit","id":studentId,"index":index},
success: function(data) {
jQuery("#studentDetailsDiv").html(data)
}
}
)
}
In editStudentDetails() method I have method ajax call to go editForm() of the controller.
Here is my controller:
#Controller
public class StudentDetailsController {
#Autowired
private StudentDetailsDAO studentDetailsDAO;
#RequestMapping(value="/studentdetails.htm",method = RequestMethod.GET)
public String initForm(HttpServletRequest request,ModelMap map){
String action=request.getParameter("action");
StudentDetailsCommand command=new StudentDetailsCommand();
System.out.println("in controller"+action);
command.setStudents(studentDetailsDAO.findAll());
map.addAttribute("command", command);
return "studentdetails";
}
#RequestMapping(value="/editstudentdetails.htm",method = RequestMethod.GET)
public String editForm(ModelMap map,HttpServletRequest request){
map.addObject("index", request.getParameter("index"));
StudentDetailsCommand command=(StudentDetailsCommand)map.get("command");
System.out.println(command);
System.out.println(command.getStudents());//NullPointerException here.
map.addObject("command", command);
return "studentdetails";
}
}
Even tried #ModelAttribute("studentDetailsCommand") but didn't worked.
I am new to Spring 3.0 and I followed all solutions which are given here but nothing worked.Can anyone help me out please?
Model attributes only exist during the life cycle of one HttpServletRequest. Consider reading my answer here.
In your initForm method, you do the following
map.addAttribute("command", command);
this add an attribute named command to the model attributes. This attribute will eventually find its way into the HttpServletRequest attributes and be available to your JSP. In here
<form:form [...] modelAttribute="studentDetailsCommand" commandName="command">
first of all, modelAttribute and commandName have the same purpose, ie. to find an attribute in the model. If you remove commandName you will get an Exception because there is no model attribute named studentDetailsCommand. Here your commandName's value is overwriting your modelAttribute's value.
When the Servlet container is finished rendering your JSP, the rendered content is sent as the body of the HTTP response. At this point, the request has been handled and the HttpServletRequest and the model attributes are garbage collected.
When you send your new request through AJAX, there is no longer any model attribute named studentDetailsCommand (there actually never was).
Consider using Flash Attributes.
Related:
How to read flash attributes after redirection in Spring MVC 3.1?
Spring RedirectAttributes: addAttribute vs addFlashAttribute
Use of getFlashAttributes() in Spring's RedirectAttributes

Spring MVC and Request Attributes

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

How to maintain session in spring MVC?

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.

Spring MVC URL for the AbstractController

I have a controller that inherits from the org.springframework.web.servlet.mvc.AbstractController class
I have configurated it in this way:
<bean name="/gameServiceController.json" class="xx.xxx.GameController"/>
so can accepts url of this form
http://<hostname>:<port>/<context-path>/gameServiceController.json
but the customer has provided to me the requirement to write URL in this way
http://<hostname>:<port>/<context-path>/createNewGame?parameter=<value>
but I think that is not possible to map this type of URL with my controller. Anyone know the type of configuration that can be used in order to configure this type of URL mapping ?
Otherwise, is legal to ask to change the format of the URL in this way
http://<hostname>:<port>/<context-path>/gameServiceController.json?command=createNewGame&phoneNumber=<phoneNumber>
so I can manage the command parameter in the "handleRequestInternal" method of my custom controller that inherits from the org.springframework.web.servlet.mvc.AbstractController class ??
Don't use the legacy Controller framework, use annotated controllers. There, you can easily use URL templates, something like this:
#Controller
public class GameController{
#RequestMapping(value="/createNewGame?parameter={param}",
method=RequestMethod.GET)
public String createNewGame(#PathVariable String param, Model model) {
// do stuff here
return "viewName";
}
}

Categories

Resources