What is the best way to pass values from jsp to controller in Spring mvc - spring

I have a jsp page that is dynamic configured. By different choice, the page has different components, just like dropdown list, list box and datetime etc. For one choice, the page may have only two dropdown list, and by another choice, the page has more enter field. Each enter field has different name. Even one page has two dropdown lists, the two lists have different names.
Just want to get your suggestion, what is the best way to get all these values to controller in Spring MVC.

I would do it as follows:
JSP: enclose all the input fields (textbox/select/checkbox/radio) in <FORM> tags and set the action attribute of the form to call the Controller.
Controller:
Define a simple Java bean class with attributes corresponding to each of the input field in the form
Accept this class type as a parameter to the method in the controller that will be called upon <FORM> submission and annotate the parameter with #RequestBody.
See Mapping the response body with the #ResponseBody annotation for more details on completing the wiring.

Create a DTO to hold all possible form element
Class MyFormData {
private String name;
private Double salary;
private List<String> hobbies;
......
}
In controller, use #ResponseBody
#RequestMapping(value = "/something", method = RequestMethod.POST)
public void handle(#RequestBody MyFormData formData, Model model) {
...
}

If your UI is so dynamic, you might as well bite the bullet and go for a Javascript solution. Spring MVC will simply receive and return JSON as #RequestBody and #ResponseBody and not worry so much about the fundamental MVC.
JSP can only get you so far in terms of dynamic UI behavior. Once you get comfortable with JQuery and/or AngularJS, you'll never look back.

Related

Populate data in spring model

I have kept a map in the page model. While invoking the page, am fetching few items from database and will keep that in the map so that i will use it in the JSP. Mainly these items are used for populating options in dropdown.
#RequestMapping(value = "/initSystemPage")
public String initSystemPage(#ModelAttribute("systemModel") SystemModel systemModel, ModelMap modelMap) {
Map<String, List<DropdownVO>> data = ** fetch items from database **;
systemModel.setData(data);
return "system";
}
Upon invoking the screen, i can get the items from the model and populate the values in the dropdown. So far fine. but the issue happens if i do any action like submitting the form. As am not keep an element in the JSP corresponding to the data attribute, upon submitting the form dropdown data is not mapped to model hence it is not available in the JSP after page refresh.
I dont want to populate the items in model in every action methods. if i keep the data in session attributes, is it possible to do the populate in a common method that need to be invoked in all actions? something like init-binder
If you want to keep your current design you can make use of #SessionAttributes annotation at class level to ensure that your systemModel attribute is stored in session and is accessible for subsequent requests. However make sure that you clear the attribute when you have completed form processing using SessionStatus. For example
#Controller
#SessionAttributes("systemModel")
public SystemPageController{
#RequestMapping(value = "/initSystemPage" , method = RequestMethod.GET)
public String initSystemPage(#ModelAttribute("systemModel") SystemModel systemModel, ModelMap modelMap) {
Map<String, List<DropdownVO>> data = ** fetch items from database **;
systemModel.setData(data);
return "system";
}
}
Alternatively you can use #ModelAttribute annotation to indicate methods which should be called for every request for the Controller to add model data.
#ModelAttribute("systemModel")
public SystemModel populateSystemModel(){
//code to populate and return
}
The signature is very flexible. You can include most parameters used with #RequestMapping methods such as HttpServletRequest #RequestParam , #PathVaribale etc

#ModelAttribute Display Value Methods (for JSP Variables) Outside of Controller

In our Controllers we have methods for populating some Display Values used by the JSP. Example: the list of US States:
#Controller
#RequestMapping("/myURL")
public class MyController {
//...
// A US State ModelAttribute populator used by JSP
#ModelAttribute("us_states")
public TreeMap<String,String> getStateDisplayValues()
{
// ... Code to populate US states for a dropdown
}
}
In JSP:
<form:select path="state">
<form:options items="${us_states}" />
</form:select>
But a concern came up that the Controller shouldn't have this method, it should go in a different place, like the Model. Maybe we are violating some MVC principle by defining these methods in the Controller.
However when I tried moving these #ModelAttribute methods to my Model object, the JSP stopped working. What is the proper place to put these JSP variables? Do I just create Model fields on top of my "regular" model to support them?
#ModelAttribute only supported for controller classes with #RequestMapping methods, so you can't move to your Model object.
us_states not a JSP variables, its a global variable within the scope of controller associated to Model object while passing to JSP.
I prefer using #ModelAttribute if there is one time static data has to load from database(like states), instead of calling every time or otherwise, you can put the states in Enum and pass it to JSP.

In MVC how is the data passed from JSP to Controller?

I'm following the Spring MVC tutorial here: http://www.tutorialspoint.com/spring/spring_mvc_form_handling_example.htm
and I'm not getting the logic how is the data passed from JSP to Controller.
I think I understand how the data is passed from the Controller to the JSP, but after the user has edited the form on the JSP how is the data passed to the Controller?
In the controller:
public String addStudent(#ModelAttribute("SpringWeb")Student student, ModelMap model)
question:
How the controller knows that from the form on the jsp Student class instance student with name, age and id are passed?
I have this example working. I have altered the example to display a list of students, but I am not able to get the list from JSP to Controller:
#RequestMapping(value = "/student", method = RequestMethod.POST)
public ModelAndView studentSave(#ModelAttribute("listOfStudents") ArrayList<Student> listOfStudents,ModelMap model)
{
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
StudentJDBCTemplate studentJDBCTemplate = (StudentJDBCTemplate) context.getBean("studentJDBCTemplate");
System.out.println("Size of listOfStudents is = " + listOfStudents.size());
...
listOfStudents.size() returns 0.
question: what am i missing here, why I can't get the list from the form on the jsp?
question: How the controller knows that from the form on the jsp
Student class instance student with name, age and id are passed?
When you submit the form you are making an HTTP (typically, POST) request to a given URL. This POST request will contain the values in
the form as request parameters. If you were not using any web framework (e.g. Spring MVC) then you would typically work directly with the Servlet API
to extract and work with these values, particularly the HttpServletRequest object.
http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html
You can try this is your application by adding the following (the Spring MVC framework will automatically pass in the request).
public String addStudent(#ModelAttribute Student student, HttpServletRequest request){
for(String key : request.getParameterMap().keySet()){
System.out.println(key + "=" + request.getParameterMap().get(key);
}
}
Now, regardless of the framework you are using the underlying mechanism does not change, the parameters are still sent in the POST request as simple Strings.
The framework however essentially adds an abstraction layer on top of this to prevent you having to write boilerplate to extract and manually work with these
parameters. So, rather than having to do the following:
public String addStudent(HttpServletRequest request){
Student student = new Student();
student.setId(Integer.parseInt(request.getParameter("id"));
student.setName(request.getParameter("name"));
....
}
you let the framework take care of it.
public String addStudent(#ModelAttribute Student student){
}
The #ModelAttribute tells the framework you want the submitted parameters to be bound to a Student instance. On submit, the framework will create a new Student
instance and, by means of reflection, (http://docs.oracle.com/javase/tutorial/reflect/) set the various fields to the corresponding HTTP params.
As for the 2nd part of your question there are numerous examples of how to bind to a Collection. See below for example:
http://viralpatel.net/blogs/spring-mvc-multi-row-submit-java-list/
Generally 'work' is done in the controller, and the results are passed to the JSP simply for display. The JSP renders to the user's browser over HTTP and then the user modifies the page and posts back to the controller.
If you're doing 'work' in the JSP that needs to be passed back to the controller before the page is sent to the user, then you should consider finding a way of doing all that in the controller.
Having said this. The model that you pass to the JSP doesn't have to contain simple objects. You can pass to the JSP an object that has methods on it that performs processing. Then in the JSP you simply call one of the methods on that object.
the controller and jsp are linked together by #ModelAttribute.
example if i want to add a new student i would first link the corresponding jsp page with the student database. like
//setup add new student form
#RequestMapping(value = "/add", method = RequestMethod.GET)
public String setStudentForm(#ModelAttribute("newStudent") Student newStudent){
return "addstudent";
}
this will set up my jsp page. In jsp page i have already declared the colums like firstname, lastname which are linked with my student model.
<form:form modelAttribute="newStudent" class="form-horizontal">
<form:input id="firstName" path="firstName" type="text"/>
<form:input id="lastName" path="lastName" type="text"/>
<input type="submit" id="btnAdd" value ="add"/>
</form>
Like this i created the ling. Now when i press submit button if will land a post request and thus following method in controller will be executed.
#RequestMapping(value = "/add", method = RequestMethod.POST)
public String processStudentForm(Model model, #ModelAttribute("newStudent") #Valid Student newStudent, BindingResult result ){
newStudent.setFirstName("gurpreet");
if(result.hasErrors()){
return "addstudent";
}
studentService.add(newStudent);
model.addAttribute("message", "Added successfully");
return "redirect:/students";
}
I can also make changes in the data like i did newStudent.setFirstName("gurpreet"); before saving the object through studentService
the #RequestMapping url is same but method has changed to POST from GET as submit button have POST submission.
(#ModelAttribute("newStudent") Student newStudent)
associates our view, Model and controller alltogether.

Passing a List from Action class to jsp and From JSP to action class in struts2

I have a requirement where i am using Struts2 as well as Jqgrid in JSP.
As per my requirement i am getting a list from different action class through interceptor.
I have to pass the list to JSP and from the Jgrid url back to respective action class.
When i am using request.setAttribute and passing the same value as parameter for
jqgrid action class url its working fine
[E.g showExcelGrid.action?LIST='+"<%=request.getAttribute("LIST")%>" but when list is large its not working properly.
Please suggest some ideas.
Thanks
I am not sure how JqGrid work but below describe the way value flow both way
To send List/Map or any other collection backed object from your action class to JSP all you need to create a list property in your action class and provide its getter and setters for this
Sample Action Class
public class SampleAction extends ActionSupport{
private List<String> listForJspPage;
//getter and setter for this list property
public String execute() throws Exception{
listForJspPage=new ArrayList<String>();
listForJspPage=fill this list with values
return SUCCESS;
}
}
with above code when your action will get executed you have listForJspPage in value stack and can be accessed using OGNL
Sample JSP
<s:iterator value="listForJspPage">
// do what ever you want to fo
</s:itertor>
here value="listForJspPage" will be interpreted by S2 as getListForJspPage() in your action class to fetch the values.
For sending the value back to action class we can make sure of the setter method with a little help from OGNL like
<s:iterator value="listForJspPage">
<s:textfield name="listForJspPage['%{id}'].value" value="%{value}" />
</s:itertor>
In this we iterate over the listForJspPage List. On the textfield tag we set the name to "listForJspPage['%{id}'].value", this would result in something that looks like "listForJspPage['1'].value". which further can be seen as
getListForJsppage().get(index).setvalue(out given value);
I know this late, but I found this one today which works.
You can pass the list from one action class to another via jsp using the s:select tag of struts2 as follows:
List<String> formList //getter and setter should be there in both the action classes
<div id="divList" style="display: none;">
<s:select list="formlist" multiple="true" id="selectedList" name="formListList"></s:select>
</div>

Mapping same URL to different controllers in spring based on query parameter

I'm using spring annotation based controller. I want my URL /user/messages to map to some controller a if query parameter tag is present otherwise to some different controller b. This is required because when parameter tag is present then some more parameters can be present along with that which i want to handle in different controller to keep the implementation clean.Is there any way to do this in spring. Also is there any other elegant solution to this problem ?
You can use the params attribute of the #RequestMapping annotation to select an controller method depending on Http parameters.
See this example:
#RequestMapping(params = "form", method = RequestMethod.GET)
public ModelAndView createForm() {
...
}
#RequestMapping(method = RequestMethod.GET)
public ModelAndView list() {
...
}
It is a REST style like Spring ROO uses: if the request contains the parameter forms then the createForm handler is used, if not the list method is used.
If you want to go the Spring route, you can checkout the HandlerInterceptor mentioned here. The Interceptor can take a look at your query param and redirect the link to something else that can be caught by another SimpleUrlMapper.
The other way is to send it to a single controller and let the controller forward to another action if the query parameter is "b".

Resources