Submit form in Spring MVC 3 - explanation

I'm having trouble understanding how the presentation form in Spring 3 MVC works.

What I want to do is create a controller that will use the username and display it for him. And somehow I did it, but I really don’t understand how it works. So..

I have a form that looks like this:

<form:form method="post" modelAttribute="person"> <form:label path="firstName">First name</form:label> <form:input path="firstName" /> <br /> <form:label path="lastName">Last name</form:label> <form:input path="lastName" /> <br /> <input type="submit" value="Submit" /> </form:form> 

I also have a controller that looks like this:

 @Controller public class HomeController { @RequestMapping(value = "/", method = RequestMethod.GET) public String showHelloPage(Model model) { model.addAttribute("person", new Person()); return "home"; } @RequestMapping(value = "/", method = RequestMethod.POST) public String sayHello(Person person, Model model) { model.addAttribute("person", person); return "home"; } } 

To display a welcome message to the user, I use the following code on the JSP page:

 <c:if test="${not empty person.firstName and not empty person.lastName}"> Hello ${person.firstName} ${person.lastName}! </c:if> 

And it works (I omit the XML configuration files because they are not related to the problem).

I thought that the “modelAttribute” attribute on the form points to a bean variable that should be populated with input values ​​(as indicated by their path attributes). But it looks, it works in a completely different way. If I delete the line

 model.addAttribute("person", new Person()); 

from the showHelloPage method. I get the (general) exception "Neither BindingResult, nor ...".

Also, at the beginning the sayTHello method looked like this:

 (...) public String sayHello(@ModelAttribute("person") Person person, Model model) { (...) 

I mean, he had the annotation "ModelAttribute". I added this because in the textbooks I read, he was always present. But after I deleted it, everything went well, as before.

So my question is, what is the use of annotating "ModelAttribute"? Can I omit the "modelAttribute" attribute on a form? And the second part, what is the way (possibly an annotation) for creating the form, automatically connects the values ​​of the inputs with the corresponding properties of the bean (which will be declared as a parameter of the method)? Without the need to add an empty bean before submitting the form (how should I do it now).

Thanks for your answers (which are not links to Spring documentation, because I already read it).

+30
java spring spring-mvc forms
Sep 22 '13 at 13:58 on
source share
1 answer

In this case, the @ModelAttribute annotation @ModelAttribute used to identify the object that Spring should add as an attribute of the model. Model attributes are an abstraction of HttpServletRequest attributes. Basically, these are objects identified by some key that will find their way in the HttpServletRequest attributes. You can do this by manually adding the attribute using Model#addAttribute(String, Object) , have the annotated @ModelAttribute method @ModelAttribute or annotate the method parameter using @ModelAttribute .

What you need to understand is how Spring resolves handler method parameters and introduces arguments. To do this, use the HandlerMethodArgumentResolver interface. There are several implementation classes (see Javadoc), and each of them is responsible for resolveArgument() , returning the argument that Spring will use to invoke() your handler method through reflection. Spring will only call the resolveArgument() method if the HandlerMethodArgumentResolver method supportsParameter() returns true for a particular parameter.

The implementation of the HandlerMethodArgumentResolver in question is here ServletModelAttributeMethodProcessor , which extends from ModelAttributeMethodProcessor , which states

It resolves method arguments annotated with @ModelAttribute and processes the return values ​​from methods annotated with @ModelAttribute.

Spring (3.2) will register this HandlerMethodArgumentResolver and others

 private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() { List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>(); // Annotation-based argument resolution resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false)); resolvers.add(new RequestParamMapMethodArgumentResolver()); resolvers.add(new PathVariableMethodArgumentResolver()); resolvers.add(new ServletModelAttributeMethodProcessor(false)); resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters())); resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters())); resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory())); resolvers.add(new RequestHeaderMapMethodArgumentResolver()); resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory())); resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory())); // Type-based argument resolution resolvers.add(new ServletRequestMethodArgumentResolver()); resolvers.add(new ServletResponseMethodArgumentResolver()); resolvers.add(new HttpEntityMethodProcessor(getMessageConverters())); resolvers.add(new RedirectAttributesMethodArgumentResolver()); resolvers.add(new ModelMethodProcessor()); resolvers.add(new MapMethodProcessor()); resolvers.add(new ErrorsMethodArgumentResolver()); resolvers.add(new SessionStatusMethodArgumentResolver()); resolvers.add(new UriComponentsBuilderMethodArgumentResolver()); // Custom arguments if (getCustomArgumentResolvers() != null) { resolvers.addAll(getCustomArgumentResolvers()); } // Catch-all resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true)); resolvers.add(new ServletModelAttributeMethodProcessor(true)); return resolvers; } 

When Spring needs to call the handler method, it will iterate over the parameter types and through the list above and use the first one that supportsParameter() .

Note that two instances of ServletModelAttributeMethodProcessor are added (one after the comment //catch all ). ModelAttributeMethodProcessor has an annotationNotRequired field that tells it whether it should look for @ModelAttribute or not. The first instance should look for @ModelAttribute , the second should not. Spring does this so that you can register your own instances of HandlerMethodArgumentResolver , see comment // Custom arguments .




In particular

 @RequestMapping(value = "/", method = RequestMethod.POST) public String sayHello(Person person, Model model) { model.addAttribute("person", person); return "home"; } 

In this case, it doesn't matter if your Person parameter is annotated or not. A ModelAttributeMethodProcessor allow it and bind the form fields, i.e. query parameters into instance fields. You do not even need to add it to model , since the ModelAttributeMethodProcessor class will handle this.

In your showHelloPage() method

 model.addAttribute("person", new Person()); 

required with taglib <form> . The way it resolves its input fields.




So my question is: what is "ModelAttribute", anonnatation?

To automatically add the specified parameter (or method return value) to the model.

Can I omit the "modelAttribute" attribute on a form?

No, the form binding looks for an object in model and associates its fields with html input elements.

And the second part, what is the way (possibly an annotation) to make the form automatically bind the values ​​of the input data to the corresponding properties of the bean (which will be declared as a parameter of the method)? Without the need to add an empty bean before submitting the form (how should I do it now).

A Spring <form> tag latches onto a model attribute object and uses its fields to create input and label elements. It doesn't matter how the object ended up in the model as long as it did. If it cannot find the model attribute with the name (key) you specified, it throws exceptions, as you saw.

  <form:form method="post" modelAttribute="person"> 

An alternative to providing an empty bean is to create html yourself. Everything Spring <form> uses bean field names to create an input element. So this is

 <form:form method="post" modelAttribute="person"> <form:label path="firstName">First name</form:label> <form:input path="firstName" /> 

It creates something like

 <form method="post" action="[some action url]"> <label for="firstName">First name<label> <input type="text" name="firstName" value="[whatever value firstName field had]" /> ... 

Spring associates query parameters with instance fields using the name attribute.

+38
Sep 22 '13 at 14:12
source share



All Articles