Using Forms with ModelAttribute in Spring MVC
In a previous post I explained how to use html forms in Spring MVC passing data to the server using the annotation RequestParam in the controller. I will explain now how to do the same thing but using the annotation ModelAttribute, which is more convenient and more standard.
Configuration
We can obtain the basic template with Spring Starter in our STS:
This is our file structure:
as you see, the layout is basically the one that we used in the other example.
Lets start with the views so that we see where we are going.
Views
Imagine that we want to create an html Form with two input fields: text1 and text2, that the user will introduce. This is how our jsp will look like:
/spring-mvc-forms-example-ModelAttribute/src/main/webapp/WEB-INF/jsp/form_page.jsp
/spring-mvc-forms-example-ModelAttribute/src/main/webapp/WEB-INF/jsp/form_page.jsp
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> <%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE html> <html> <head> <link href="<c:url value="css/app.css" />" rel="stylesheet" type="text/css"> <title>Hello World!</title> </head> <body > <div class="lc-block"> <form:form method="post" action="" modelAttribute="formBean"> <h3>introduce text here</h3> <table> <tr> <td>text 1:</td> <td><form:input type="text" path="text1" /></td> </tr> <tr> <td>text 2:</td> <td><form:input type="text" path="text2" /></td> </tr> </table> <p> <input type="submit" value="Start" /> </p> </form:form> </div> </body> </html>
Two things to notice:
- The form has the label modelAttribute ="formBean" which will tell spring that the ata posted by this form will go to an object which will be a bean called formBean. The inputs have labels like path="text1" which will make spring look for attributes called text1 and text2 inside formBean.
- Although we have inserted the label action="" in our form, when the html gets generated, it will contain the path to the correct page or action.
The following code corresponds to the jsp that we will use to display the strings that we have introduced (just to prove that the server has received them):
/spring-mvc-forms-example-ModelAttribute/src/main/webapp/WEB-INF/jsp/response_page.jsp
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> <%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE html> <html> <head> <link href="<c:url value="css/app.css" />" rel="stylesheet" type="text/css"> <title>Hello World!</title> </head> <body > <div class="lc-block"> <h1> you introduced</h1> <p> "${text1}" and "${text2}"</p> </div> </body> </html>
Controller and Form spring bean
The first thing that we have to do is to create a java POJO class that will contain these two strings. This class will also be an spring bean and should have the annotation @XmlRootElement.
/spring-mvc-forms-example-ModelAttribute/src/main/java/com/hjbello/Form.java
package com.hjbello; import javax.xml.bind.annotation.XmlRootElement; import org.springframework.stereotype.Component; @Component(value="formBean") @XmlRootElement public class Form { private String text1 = ""; private String text2 = ""; public Form() { } public Form(String text1, String text2) { super(); this.text1 = text1; this.text2 = text2; } public String getText1() { return text1; } public void setText1(String text1) { this.text1 = text1; } public String getText2() { return text2; } public void setText2(String text2) { this.text2 = text2; } }
It is important that our class has the right constructors (one empty and the other with the strings) otherwise we will have problems.
The controller should know that we are using the previous spring bean:
/spring-mvc-forms-example-ModelAttribute/src/main/java/com/hjbello/HomeController.java
In HomeController we have created two RequestMappings one for the Post method and one for the Get method. Inside the one for the GET method it is important that we pass the object form into the view, otherwise we will get errors.
Using the input
@ModelAttribute("formBean") Form form
we pass our form to the controller.
The controller should know that we are using the previous spring bean:
/spring-mvc-forms-example-ModelAttribute/src/main/java/com/hjbello/HomeController.java
package com.hjbello; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; /** * Handles requests for the application home page. */ @Controller public class HomeController { private static final Logger logger = LoggerFactory.getLogger(HomeController.class); @RequestMapping(value = "/", method = RequestMethod.GET) public String home(Model model) { logger.info("....."); return "home"; } @RequestMapping(value = "/send-form", method=RequestMethod.GET) public ModelAndView formGet() { ModelAndView mv = new ModelAndView(); Form form = new Form(); mv.addObject("formBean", form); mv.setViewName("form_page"); return mv; } @RequestMapping(value = "/send-form", method=RequestMethod.POST) public ModelAndView formPost(@ModelAttribute("formBean") Form form) { ModelAndView mv = new ModelAndView(); mv.addObject("text1",form.getText1()); mv.addObject("text2",form.getText2()); mv.setViewName("response_page"); return mv; } }
In HomeController we have created two RequestMappings one for the Post method and one for the Get method. Inside the one for the GET method it is important that we pass the object form into the view, otherwise we will get errors.
Using the input
@ModelAttribute("formBean") Form form
we pass our form to the controller.