In this tutorial, we're going to discuss all Spring MVC related JSP form tags with an example.
We will use discuss below important spring MVC form tags in this tutorial:
So we all know about HTML forms, right?. We'll learn how to use forms with Spring. And in particular, Spring has support for form tags, and these are form tags that are configurable, and we can reuse them on a webpage.
Well, these Spring MVC form tags give us extra support. For example, they support data binding so this allows us to automatically set data and retrieve data from Java objects and beans.
As of version 2.0, Spring provides a comprehensive set of data binding-aware tags for handling form elements when using JSP and Spring Web MVC.
Each tag provides support for the set of attributes of its corresponding HTML tag counterpart, making the tags familiar and intuitive to use. The tag-generated HTML is HTML 4.01/XHTML 1.0 compliant.
In this tutorial, we will first discuss all the Spring' form tags and later we will see a complete end-to-end example with Spring MVC.
Let’s go through all these form tags and look at an example of how each tag is used. We have included generated HTML snippets where certain tags require further commentary.
The form tag library comes bundled in spring-webmvc.jar. The library descriptor is called spring-form.tld.
To use the tags from this library, add the following directive to the top of your JSP page:
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
where a form is the tag name prefix you want to use for the tags from this library.
The form tag
This tag renders an HTML 'form' tag and exposes a binding path to inner tags for binding. It puts the command object in the PageContext so that the command object can be accessed by inner tags. All the other tags in this library are nested tags of the form tag.
Let’s assume we have a domain object called User. It is a JavaBean with properties such as firstName and lastName. We will use it as the form backing object of our form controller which returns form.jsp. Below is an example of what form.jsp would look like:
<form:form> <table> <tr> <td>First Name:</td> <td> <form:input path="firstName" /> </td> </tr> <tr> <td>Last Name:</td> <td> <form:input path="lastName" /> </td> </tr> <tr> <td colspan="2"> <input type="submit" value="Save Changes" /> </td> </tr> </table> </form:form>
The firstName and lastName values are retrieved from the command object placed in the PageContext by the page controller.
When the form is loaded, spring MVC will call getter methods - user.getFirstName() and user.getLastName() to get the values. When the form is submitted, Spring MVC will call user.setFirstName() and user.setLastName() methods to set the values.
The generated HTML looks like a standard form:
<form method="POST"> <table> <tr> <td>First Name:</td> <td><input name="firstName" type="text" value="Harry" /></td> </tr> <tr> <td>Last Name:</td> <td><input name="lastName" type="text" value="Potter" /></td> </tr> <tr> <td colspan="2"> <input type="submit" value="Save Changes" /> </td> </tr> </table> </form>
This input tag renders an HTML 'input' tag using the bound value and type='text' by default. For an example:
<form:input path="firstName"/> <form:input path="lastName"/>
The generated HTML looks like a standard form:
<input name="firstName" type="text" value="Harry"/> <input name="lastName" type="text" value="Potter"/>
Starting with Spring 3.1 you can use other types such as HTML5-specific types like 'email', 'tel', 'date', and others.
This tag renders an HTML 'input' tag with type 'checkbox'.
Let’s assume our User has preferences such as newsletter subscription and a list of hobbies. Below is an example of the Preferences class:
public class Preferences { private boolean receiveNewsletter; private String[] interests; private String favouriteWord; public boolean isReceiveNewsletter() { return receiveNewsletter; } public void setReceiveNewsletter(boolean receiveNewsletter) { this.receiveNewsletter = receiveNewsletter; } public String[] getInterests() { return interests; } public void setInterests(String[] interests) { this.interests = interests; } public String getFavouriteWord() { return favouriteWord; } public void setFavouriteWord(String favouriteWord) { this.favouriteWord = favouriteWord; } }
The form.jsp would look like:
<form:form> <table> <tr> <td>Subscribe to newsletter?:</td> <%-- Approach 1: Property is of type java.lang.Boolean --%> <td> <form:checkbox path="preferences.receiveNewsletter" /> </td> </tr> <tr> <td>Interests:</td> <%-- Approach 2: Property is of an array or of type java.util.Collection --%> <td> Quidditch: <form:checkbox path="preferences.interests" value="Quidditch" /> Herbology: <form:checkbox path="preferences.interests" value="Herbology" /> Defence Against the Dark Arts: <form:checkbox path="preferences.interests" value="Defence Against the Dark Arts" /> </td> </tr> <tr> <td>Favourite Word:</td> <%-- Approach 3: Property is of type java.lang.Object --%> <td> Magic: <form:checkbox path="preferences.favouriteWord" value="Magic" /> </td> </tr> </table> </form:form>
There are 3 approaches to the checkbox tag which should meet all our checkbox needs.
Note that regardless of the approach, the same HTML structure is generated. Below is an HTML snippet of some checkboxes:
<tr> <td>Interests:</td> <td> Quidditch: <input name="preferences.interests" type="checkbox" value="Quidditch" /> <input type="hidden" value="1" name="_preferences.interests" /> Herbology: <input name="preferences.interests" type="checkbox" value="Herbology" /> <input type="hidden" value="1" name="_preferences.interests" /> Defence Against the Dark Arts: <input name="preferences.interests" type="checkbox" value="Defence Against the Dark Arts" /> <input type="hidden" value="1" name="_preferences.interests" /> </td> </tr>
This tag renders multiple HTML 'input' tags with type 'checkbox'.
Below is an example of the JSP using this tag:
<form:form> <table> <tr> <td>Interests:</td> <td> <%-- Property is of an array or of type java.util.Collection --%> <form:checkboxes path="preferences.interests" items="${interestList}" /> </td> </tr> </table> </form:form>
This tag renders an HTML 'input' tag with type 'radio'.
A typical usage pattern will involve multiple tag instances bound to the same property but with different values.
<tr> <td>Sex:</td> <td> Male: <form:radiobutton path="sex" value="M" /> <br/> Female: <form:radiobutton path="sex" value="F" /> </td> </tr>
This tag renders multiple HTML 'input' tags with type 'radio'. For example:
<tr> <td>Sex:</td> <td> <form:radiobuttons path="sex" items="${sexOptions}" /> </td> </tr>
This tag renders an HTML 'input' tag with type 'password' using the bound value.
<tr> <td>Password:</td> <td> <form:password path="password" /> </td> </tr>
Please note that by default, the password value is not shown. If you do want the password value to be shown, then set the value of the 'showPassword' attribute to true, like so.
<tr> <td>Password:</td> <td> <form:password path="password" value="^76525bvHGq" showPassword="true" /> </td> </tr>
This tag renders an HTML 'select' element. It supports data binding to the selected option as well as the use of nested options and options tags.
Let’s assume a User has a list of skills.
<tr> <td>Skills:</td> <td> <form:select path="skills" items="${skills}" /> </td> </tr>
If the User’s skill were in Herbology, the HTML source of the 'Skills' row would look like:
<tr> <td>Skills:</td> <td> <select name="skills" multiple="true"> <option value="Potions">Potions</option> <option value="Herbology" selected="selected">Herbology</option> <option value="Quidditch">Quidditch</option> </select> </td> </tr>
This tag renders an HTML 'option'. It sets 'selected' as appropriate based on the bound value.
<tr> <td>House:</td> <td> <form:select path="house"> <form:option value="Gryffindor" /> <form:option value="Hufflepuff" /> <form:option value="Ravenclaw" /> <form:option value="Slytherin" /> </form:select> </td> </tr>
If the User’s house was in Gryffindor, the HTML source of the 'House' row would look like:
<tr> <td>House:</td> <td> <select name="house"> <option value="Gryffindor" selected="selected">Gryffindor</option> <option value="Hufflepuff">Hufflepuff</option> <option value="Ravenclaw">Ravenclaw</option> <option value="Slytherin">Slytherin</option> </select> </td> </tr>
This tag renders a list of HTML 'option' tags. It sets the 'selected' attribute as appropriate based on the bound value.
<tr> <td>Country:</td> <td> <form:select path="country"> <form:option value="-" label="--Please Select" /> <form:options items="${countryList}" itemValue="code" itemLabel="name" /> </form:select> </td> </tr>
If the User lived in the UK, the HTML source of the 'Country' row would look like:
<tr> <td>Country:</td> <td> <select name="country"> <option value="-">--Please Select</option> <option value="AT">Austria</option> <option value="UK" selected="selected">United Kingdom</option> <option value="US">United States</option> </select> </td> </tr>
This tag renders an HTML 'textarea'.
<tr> <td>Notes:</td> <td> <form:textarea path="notes" rows="3" cols="20" /> </td> <td> <form:errors path="notes" /> </td> </tr>
This tag renders an HTML 'input' tag with type 'hidden' using the bound value. To submit an unbound hidden value, use the HTML input tag with type 'hidden'.
<form:hidden path="house"/>
If we choose to submit the 'house' value as a hidden one, the HTML would look like this:
<input name="house" type="hidden" value="Gryffindor"/>
This tag renders field errors in an HTML 'span' tag. It provides access to the errors created in your controller or those that were created by any validators associated with your controller.
Let’s assume we want to display all error messages for the firstName and lastName fields once we submit the form. We have a validator for instances of the User class called UserValidator.
public class UserValidator implements Validator { public boolean supports(Class candidate) { return User.class.isAssignableFrom(candidate); } public void validate(Object obj, Errors errors) { ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "required", "Field is required."); ValidationUtils.rejectIfEmptyOrWhitespace(errors, "lastName", "required", "Field is required."); } }
The form.jsp would look like:
<form:form> <table> <tr> <td>First Name:</td> <td> <form:input path="firstName" /> </td> <!-- Show errors for firstName field --> <td> <form:errors path="firstName" /> </td> </tr> <tr> <td>Last Name:</td> <td> <form:input path="lastName" /> </td> <!-- Show errors for lastName field --> <td> <form:errors path="lastName" /> </td> </tr> <tr> <td colspan="3"> <input type="submit" value="Save Changes" /> </td> </tr> </table> </form:form>
If we submit a form with empty values in the firstName and lastName fields, this is what the HTML would look like:
<form method="POST"> <table> <tr> <td>First Name:</td> <td><input name="firstName" type="text" value="" /></td> <!-- Associated errors to firstName field displayed --> <td><span name="firstName.errors">Field is required.</span></td> </tr> <tr> <td>Last Name:</td> <td><input name="lastName" type="text" value="" /></td> <!-- Associated errors to lastName field displayed --> <td><span name="lastName.errors">Field is required.</span></td> </tr> <tr> <td colspan="3"> <input type="submit" value="Save Changes" /> </td> </tr> </table> </form>
What if we want to display the entire list of errors for a given page? The example below shows that the errors tag also supports some basic wildcarding functionality.
path="*" - displays all errors
path="lastName" - displays all errors associated with the lastName field
if a path is omitted - object errors only are displayed
The example below will display a list of errors at the top of the page, followed by field-specific errors next to the fields:
<form:form> <form:errors path="*" cssClass="errorBox" /> <table> <tr> <td>First Name:</td> <td> <form:input path="firstName" /> </td> <td> <form:errors path="firstName" /> </td> </tr> <tr> <td>Last Name:</td> <td> <form:input path="lastName" /> </td> <td> <form:errors path="lastName" /> </td> </tr> <tr> <td colspan="3"> <input type="submit" value="Save Changes" /> </td> </tr> </table> </form:form>
The HTML would look like this:
<form method="POST"> <span name="*.errors" class="errorBox">Field is required.<br/>Field is required.</span> <table> <tr> <td>First Name:</td> <td><input name="firstName" type="text" value="" /></td> <td><span name="firstName.errors">Field is required.</span></td> </tr> <tr> <td>Last Name:</td> <td><input name="lastName" type="text" value="" /></td> <td><span name="lastName.errors">Field is required.</span></td> </tr> <tr> <td colspan="3"> <input type="submit" value="Save Changes" /> </td> </tr> </table> </form>
Starting with Spring 3, the Spring form tag library allows entering dynamic attributes, which means you can enter any HTML5 specific attributes.
In Spring 3.1, the form input tag supports entering a type attribute other than 'text'. This is intended to allow rendering new HTML5 specific input types such as 'email', 'date', 'range', and others. Note that entering type='text' is not required since 'text' is the default type.
Let's create a simple Spring MVC project to demonstrate the usage of a few Spring MVC form tags with JSP.
In this example, we will use a Java-based configuration that is we configure the Spring Dispatcher Servlet and spring beans configuration using all Java Code (no XML).
Follow below 11 development steps to develop a complete end-to-end Spring MVC form handling application.
Let's create a Maven-based web application either using a command line or from Eclipse IDE.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>net.javaguides.springmvc</groupId> <artifactId>springmvc5-form-tags</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>springmvc5-form-tags Maven Webapp</name> <url>http://maven.apache.org</url> <properties> <failOnMissingWebXml>false</failOnMissingWebXml> </properties> <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.0.RELEASE</version> </dependency> <!-- JSTL Dependency --> <dependency> <groupId>javax.servlet.jsp.jstl</groupId> <artifactId>javax.servlet.jsp.jstl-api</artifactId> <version>1.2.1</version> </dependency> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency> <!-- Servlet Dependency --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!-- JSP Dependency --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.1</version> <scope>provided</scope> </dependency> </dependencies> <build> <sourceDirectory>src/main/java</sourceDirectory> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
Note that we are using spring-webmvc dependency for a Spring MVC web application.
Next, let's create a standard project structure, please refer to the below diagram.
Standard project structure for your reference -
As the name suggests Spring MVC, look at the above diagram we are using the Model-View-Controller approach.
Model - User.java
Views - user.jsp, users.jsp
Controller - UserController.java
Next step, we will configure Spring beans using Java-based configuration.
Create an MVCConfig class and annotated it with @Configuration, @EnableWebMvc, and @ComponentScan annotations.
package net.javaguides.springmvc.form.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.JstlView; @Configuration @EnableWebMvc @ComponentScan(basePackages = { "net.javaguides.springmvc.form" }) public class MVCConfig implements WebMvcConfigurer { @Bean public InternalResourceViewResolver resolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setViewClass(JstlView.class); resolver.setPrefix("/WEB-INF/views/"); resolver.setSuffix(".jsp"); return resolver; } }
In Spring MVC, The DispatcherServlet needs to be declared and mapped for processing all requests either using java or web.xml configuration.
In a Servlet 3.0+ environment, you can use AbstractAnnotationConfigDispatcherServletInitializer class to register and initialize the DispatcherServlet programmatically as follows.
package net.javaguides.springmvc.form.config; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class SpringMvcDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class << ? > [] getRootConfigClasses() { // TODO Auto-generated method stub return null; } @Override protected Class << ? > [] getServletConfigClasses() { return new Class[] { MVCConfig.class }; } @Override protected String[] getServletMappings() { return new String[] { "/" }; } }
Let's create a User Java class for binding data to the model and rendering model data on views.
package net.javaguides.springmvc.form.model; public class User { private String username; private String password; private String address; private boolean receivePaper; private String[] favoriteFrameworks; private String gender; private String favoriteNumber; private String country; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public boolean isReceivePaper() { return receivePaper; } public void setReceivePaper(boolean receivePaper) { this.receivePaper = receivePaper; } public String[] getFavoriteFrameworks() { return favoriteFrameworks; } public void setFavoriteFrameworks(String[] favoriteFrameworks) { this.favoriteFrameworks = favoriteFrameworks; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public String getFavoriteNumber() { return favoriteNumber; } public void setFavoriteNumber(String favoriteNumber) { this.favoriteNumber = favoriteNumber; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } }
Let's create a UserController controller class annotated with @Controller annotation as follows:
package net.javaguides.springmvc.form.controller; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; 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; import net.javaguides.springmvc.form.model.User; @Controller public class UserController { @RequestMapping(value = "/user", method = RequestMethod.GET) public ModelAndView user() { User user = new User(); user.setFavoriteFrameworks((new String[] { "Spring MVC", "Struts 2" })); user.setGender("M"); ModelAndView modelAndView = new ModelAndView("user", "command", user); return modelAndView; } @RequestMapping(value = "/addUser", method = RequestMethod.POST) public String addUser(@ModelAttribute("SpringWeb") User user, ModelMap model) { model.addAttribute("username", user.getUsername()); model.addAttribute("password", user.getPassword()); model.addAttribute("address", user.getAddress()); model.addAttribute("receivePaper", user.isReceivePaper()); model.addAttribute("favoriteFrameworks", user.getFavoriteFrameworks()); model.addAttribute("gender", user.getGender()); model.addAttribute("favoriteNumber", user.getFavoriteNumber()); model.addAttribute("country", user.getCountry()); return "users"; } @ModelAttribute("webFrameworkList") public Object[] getWebFrameworkList() { List < String > webFrameworkList = new ArrayList < String > (); webFrameworkList.add("Spring MVC"); webFrameworkList.add("Struts 1"); webFrameworkList.add("Struts 2"); webFrameworkList.add("Apache Wicket"); return webFrameworkList.toArray(); } @ModelAttribute("numbersList") public List < String > getNumbersList() { List < String > numbersList = new ArrayList < String > (); numbersList.add("1"); numbersList.add("2"); numbersList.add("3"); numbersList.add("4"); return numbersList; } @ModelAttribute("countryList") public Map < String, String > getCountryList() { Map < String, String > countryList = new HashMap < String, String > (); countryList.put("US", "United States"); countryList.put("CH", "China"); countryList.put("SG", "Singapore"); countryList.put("MY", "Malaysia"); return countryList; } }
user.jsp
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form" %> <%@ page isELIgnored="false" %> <html> <head> <title>Spring MVC Form Handling</title> </head> <body> <h2>User Information</h2> <form:form method="POST" action="addUser"> <table> <tr> <td> <form:label path="username">User Name</form:label> </td> <td> <form:input path="username" /> </td> </tr> <tr> <td> <form:label path="password">Password</form:label> </td> <td> <form:password path="password" /> </td> </tr> <tr> <td> <form:label path="address">Address</form:label> </td> <td> <form:textarea path="address" rows="5" cols="30" /> </td> </tr> <tr> <td> <form:label path="receivePaper">Subscribe Newsletter</form:label> </td> <td> <form:checkbox path="receivePaper" /> </td> </tr> <tr> <td> <form:label path="favoriteFrameworks">Favorite Web Frameworks</form:label> </td> <td> <form:checkboxes items="${webFrameworkList}" path="favoriteFrameworks" /> </td> </tr> <tr> <td> <form:label path="gender">Gender</form:label> </td> <td> <form:radiobutton path="gender" value="M" label="Male" /> <form:radiobutton path="gender" value="F" label="Female" /> </td> </tr> <tr> <td> <form:label path="favoriteNumber">Favorite Number</form:label> </td> <td> <form:radiobuttons path="favoriteNumber" items="${numbersList}" /> </td> </tr> <tr> <td> <form:label path="country">Country</form:label> </td> <td> <form:select path="country"> <form:option value="NONE" label="Select" /> <form:options items="${countryList}" /> </form:select> </td> </tr> <tr> <td colspan="2"> <input type="submit" value="Submit" /> </td> </tr> </table> </form:form> </body> </html>
users.jsp
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form" %> <html> <head> <title>Spring MVC Form Handling</title> <%@ page isELIgnored="false" %> </head> <body> <h2>Submitted User Information</h2> <table> <tr> <td>Username</td> <td>${username}</td> </tr> <tr> <td>Password</td> <td>${password}</td> </tr> <tr> <td>Address</td> <td>${address}</td> </tr> <tr> <td>Subscribed to Newsletter</td> <td>${receivePaper}</td> </tr> <tr> <td>Favorite Web Frameworks</td> <td> <% String[] favoriteFrameworks = (String[])request.getAttribute("favoriteFrameworks"); %> <% for(String framework: favoriteFrameworks) { %> <%= framework %><br /> <% } %> </td> </tr> <tr> <td>Gender</td> <td><%= (gender=="M"? "Male" : "Female") %></td> </tr> <tr> <td>Favourite Number</td> <td>${favoriteNumber}</td> </tr> <tr> <td>Country</td> <td>${country}</td> </tr> </table> </body> </html>
As we are using the maven build tool so first, we will need to build this application using the following maven command:
clean install
Once build success, then we will run this application on tomcat server 8.5 in IDE or we can also deploy war file on external tomcat webapps folder and run the application.
Once an application is up and running in tomcat server then hit this link into browser: http://localhost:8080/springmvc5-form-tags/user
On entering the URL, you will see the following page.
Fill the above user information form and hit submit button will navigate to users information page as shown below:
That's all about Spring's form tags.