Why isn't my id preserved of the #ModelAttribute? - spring

Why isn't my id preserved of the #ModelAttribute? Why do I have to send it as a hidden parameter in my form? Shouldn't spring handle this when using command?
#RequestMapping(value="/{supplierId}", method=RequestMethod.GET)
public String get(#PathVariable Long supplierId, Model model, Principal principal){
Form form = .... //Got a an existing form from DB
model.addAttribute("form", form);
return "/form";
}
#RequestMapping(value="/{supplierId}", method=RequestMethod.POST)
public String post(HttpServletRequest request, #PathVariable Long supplierId, #Valid #ModelAttribute("form") Form form, BindingResult result, Model model, Principal principal){
System.out.println(form.getID()); //Here the id is 0
safeFoodFormService.store(form, supplierId);
return "redirect:/supplier";
}
My Freemarker form
<form class="form-horizontal" action="<#spring.url "/forms/${supplier.ID?c}"/>" method="post" command="form">
It will work if I do add this lines inside my form
<#spring.bind "form.ID" />
<input type="hidden" name="${spring.status.expression}" value="${spring.status.value default("")}" />
I would be very nice if this could be handled by Spring. Thanks

Spring data binding takes the request name/value pair and binds the corresponding properties with same name to corresponding value. So if there is no id request parameter present in request, spring mvc has no way to map its value in the model bean which would be injected in to the controller method. So by any mechanism the form must have a input (hidden or otherwise) to let the spring bind its value to the bean property.

Related

Spring is not showing validation error for Dynamically generated Form Id

Spring validation works fine for a form with static id. But in my scenario forms are generated dynamically on frontend.
For Example - My form bean is - GenericQuestionnaireForm so if i have the form element as below
<form:form method="post" modelAttribute="genericQuestionnaireForm" action="/save-generic-questionnaire">
validation works fine and the errors are correctly displayed.
But I have to capture the form values for different products so I am generating different forms with unique id by attaching the form name with the product number.
<form:form method="post" modelAttribute="product1_genericQuestionnaireForm" action="/save-generic-questionnaire">
when I submit this form to my controller method the BindingResult are getting attached to the genericQuestionnaireForm form object due to which the errors are not getting displayed on front end.
#RequestMapping(value = "/save-generic-questionnaire", method = RequestMethod.POST)
public String saveQuestionnaire(#Valid final GenericQuestionnaireForm genericQuestForm,final BindingResult bindingResult, final Model model,
final RedirectAttributes redirectModel, final HttpServletRequest request) throws CMSItemNotFoundException{
if(genericQuestForm != null) {
genericQuestionnaireFormValidator.validate(genericQuestForm, bindingResult);
if (bindingResult.hasErrors())
{ return //to the front end..}
}
My query is - Is there a way to attach the BindingResult to the dynamic form Id in order to show the generated errors. Or is there a better way to do form validation in this scenario?
<<form:form:form method="post" modelAttribute="genericQuestionnaireForm" action="/save-generic-questionnaire" >
<form:hidden path="id"/>
.................
</form:form>
modelAttribute attribute always remains the same.
#ModelAttribute("genericQuestionnaireForm")
public genericQuestionnaireForm getgenericQuestionnaireForm(){
return new genericQuestionnaireForm();
}
RequestMapping(value = "/save-generic-questionnaire", method =
RequestMethod.POST)
public String saveQuestionnaire(#Valid final GenericQuestionnaireForm genericQuestForm, BindingResult bindingResult.....
for identifing different products just use hidden id.

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.

Data binding without using spring taglib

My html is built without using the spring taglib and now I'd like to bind the parameters of the form to a object in my controller.
Currently my form looks like this
<form>
<input type="text" name="frAccUserMgmt.userName"/>
<input type="password" name="frAccUserMgmt.userPwd"/>
</form>
The relevant part of my object is
Class FrAccUserMgmt {
private String userName;
private Strint userPwd;
// getter and setter
}
My controller is
#RequestMapping("login")
Public ModelAndView doLogin(FrAccUserMgmt frAccUserMgmt) {
//code
}
How do I go about binding it. Currently the binding doesn't happen. I just get an empty object in my code.
You could try including the BindingResult class in the method signature and then see if there are any binding errors:
#RequestMapping("login")
Public ModelAndView doLogin(FrAccUserMgmt frAccUserMgmt, BindingResult result) {
if (result.hasErrors()) {
logger.warn("BindingResult errors: " + result.toString());
}
//code
}
Remove the frAccUserMgmt part from the form field names. Spring will automatically find the command object to bind the request parameters based on the getters and setters defined in the command object.
This can also be done by adding the #ModelAttribute for the parameter bean that should be populated with the request parameters.
As per spring docs
http://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-ann-modelattrib-method-args
(16.3.3.8 Using #ModelAttribute on a method argument)
An #ModelAttribute on a method argument indicates the argument should be retrieved from the model. If not present in the model, the argument should be instantiated first and then added to the model. Once present in the model, the argument's fields should be populated from all request parameters that have matching names. This is known as data binding in Spring MVC, a very useful mechanism that saves you from having to parse each form field individually.

Spring 3 MVC, multipart form and controller mapping issue

My application uses submit name as action name consistently. It has worked so far.
Enter multipart form...
html
<form:form modelAttribute="screenObject" enctype="multipart/form-data">
<input name="save" value="Save" type="submit" />
Controller
public static final String ACTION_SAVE="save";
#RequestMapping(method=RequestMethod.POST, params=ACTION_SAVE)
public ModelAndView save(#ModelAttribute("screenObject") FileHeaderEditScreenObject screenObject, BindingResult bindingResult, Model model, Locale locale) {
Error
message Request method 'POST' not supported
If I remove enctype="multipart/form-data", control flows right into the save method. I do need different actions on this multipart form. I want to stay consitent so I hope I do not have to introduce any hidden fields to represent actions or submit the form to different urls...
I suggest to remove params=ACTION_SAVE from the annotation.
It look like that it doesn't parse submit action from a multipart request.
You can handle that parameter as a request parameter:
#RequestMapping(method=RequestMethod.POST, params=ACTION_SAVE)
public ModelAndView save(
#RequestParam(value = "submit", required = true) String action,
#ModelAttribute("screenObject") ....
{
switch (action) {
case "action1": ...
case "action2": ...
}
}
This is not very nice. I would just use different URLs like this:
#RequestMapping("/action1"})
public void action1(
#RequestMapping("/action2"})
public void action2(

send an object via post

I want to make a form in which I can update my entity in my REST application. For example I have a User entity whith username and realname fields.
Do I need in my request method do something like this
#RequestMapping(value = "/admin/user/update", method = RequestMethod.POST)
public String updateHouse(#RequestBody String username, #RequestBody String realname, Model model)
??
I would prefer to make something like this
#RequestMapping(value = "/admin/house/update", method = RequestMethod.POST)
public String updateHouse(#RequestBody User user, Model model)
I mean that I want to send an object not every field. If i`ll have 20 fields in my entity I would have to add 20 params to my method. Thats not to fancy.
I`m using spring form tag
------- UPDATE
thanks for response. below diffrent entity but real case scenario that i`m trying to start
html code
<c:url var="houseUpdateLink" value="/admin/house/update" />
<form:form method="post" commandName="house" action="${houseUpdateLink}">
<form:input path="house.title" />
<input type="submit" value="send" />
</form:form>
controller method
#RequestMapping(value = "/admin/house/update", method = RequestMethod.POST)
public String updateHouse(#RequestBody House house, Model model) {
model.addAttribute("step", 3);
logger.info("test: " + house.getTitle());
return "houseAdmin";
}
and i receive
HTTP Status 415 -
type Status report
message
description The server refused this request because the request entity is in a format not supported by the requested resource for the requested method ().
You don't need #RequestBody here. Spring will automatically bind the form fields to the House class without it, i.e.
#RequestMapping(value = "/admin/house/update", method = RequestMethod.POST)
public String updateHouse(House house, Model model) {
In the Spring form tags, you can probably do user.username, and pass the User object as a param.

Resources