Spring MVC JSP Form Tags Example



In this quick article, we will discuss all Spring MVC JSP form tags with sample code examples.

These Spring MVC form tags, they give us extra support. 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.

Spring’s form tag library

  • The form tag
  • The input tag
  • The checkbox tag
  • The checkboxes tag
  • The radiobutton tag
  • The radiobuttons tag
  • The password tag
  • The select tag
  • The option tag
  • The options tag
  • The textarea tag
  • The hidden tag
  • The errors tag
  • HTML5 tags
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.

Configuration

The form tag library comes bundled in spring-webmvc.jar. The library descriptor is called spring-form.tld.

How To Reference Spring MVC Form Tags

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 class user.getFirstName() and getLastName() (getter methods). When the form is submitted, Spring MVC will call user.setFirstName() and user.setLastName() methods.
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>

The input tag

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.

The checkbox tag

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.
  1. Approach One - When the bound value is of type java.lang.Boolean, the input(checkbox) is marked as 'checked' if the bound value is true. The value attribute corresponds to the resolved value of the setValue(Object) value property.
  2. Approach Two - When the bound value is of type array or java.util.Collection, the input(checkbox) is marked as 'checked' if the configured setValue(Object) value is present in the bound Collection.
  3. Approach Three - For any other bound value type, the input(checkbox) is marked as 'checked' if the configured setValue(Object) is equal to the bound value.
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>

The checkboxes tag

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>

The radiobutton tag

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>

The radiobuttons tag

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>

The password tag

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>

The select tag

This tag renders an HTML 'select' element. It supports data binding to the selected option as well as the use of nested option 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>

The option tag

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>

The options tag

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>

The textarea tag

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>

The hidden tag

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:
<input name="house" type="hidden" value="Gryffindor"/>

The errors tag

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:
<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>

HTML5 tags

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.

Check out a complete example and tutorial of Spring MVC form tags at Spring MVC JSP Form Tags Tutorial

Comments