Spring Framework has built-in integration for using Spring MVC with JSP and JSTL.
View Resolvers
When
developing JSP, it is common to declare an InternalResourceViewResolver
bean.
InternalResourceViewResolver
can be used to dispatch to any servlet resource, but especially to JSPs. As a best practice, we strongly recommend
placing JSP files in a directory under the "WEB-INF"
directory so that clients cannot access them
directly.
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
JSPs vs. JSTL
When using the JSP Standard Tag Library (JSTL), you must use a special view
class JstlView
, since JSTL requires some preparation for things like I18N functions to work.
JSP tag library for Spring
Spring provides binding of request parameter data to objects commands as described in previous chapters. To make it easier to develop JSP pages in conjunction with these data binding features, Spring provides several tags that make things even easier. All Spring tags have HTML escaping features that can be enabled or disabled to escape characters.
The spring.tld
tag library (TLD)
descriptor is included in spring-webmvc.jar
. For comprehensive information on individual tags, view API reference or refer to the tag library description.
Spring Form Tag Library
Since version 2.0 Spring provides a full set of tags that support data binding for working with form elements when using JSP and Spring Web MVC. Each tag provides support for a set of attributes of the corresponding HTML tag counterpart, which makes the tags familiar and intuitive to use. The HTML generated by the tags complies with HTML 4.01/XHTML 1.0 standards.
Unlike other form/input tag libraries, the Form Tag Library for Spring is integrated with Spring Web MVC, allowing tags to have access to command object and reference data , which your controller works with. As shown in the following examples, form tags make JSPs easier to develop, read, and maintain.
We'll walk through form tags and look at an example of how to use each tag. We have included generated HTML fragments where certain tags require additional comments.
Configuration
Form tag library included from spring-webmvc.jar
.
The library descriptor is called spring-form.tld
.
To use 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 form
is the prefix of the tag name that you want to use for tags from this library.
Form tag
This tag renders the HTML "form" element and exposes the
binding path to internal tags for anchoring. It places the command object in a PageContext
so that the
command object can be accessed by internal tags. All other tags in this library are subtags of the form
tag.
Suppose we have a domain object called User
. It is a JavaBean with properties like firstName
and lastName
. We can use it as the base form object of our form controller, which returns a form.jsp
file. The following example shows what form.jsp
might 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
PageContext
by the page controller. Continue reading to see more advanced examples of using inner tags
with the form
tag.
The following listing shows the generated HTML, which 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 previous JSP assumes that the variable name of the underlying form object is command
. If you
placed the underlying form object in the model under a different name (definitely the best option), you can bind the
form to a named variable, as shown in the following example:
<form:form modelAttribute="user">
<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 input
tag
This tag renders the HTML element input
with a bound value
and type='text'
by default. You can also use HTML5-specific types such as email
,
tel
, date
and others.
The checkbox
tag
This tag renders an
HTML input
tag with type
set to checkbox
.
Let's assume that our
User
has personal user parameters such as a newsletter subscription and a list of hobbies. The
following example shows 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;
}
}
class Preferences(
var receiveNewsletter: Boolean,
var interests: StringArray,
var favouriteWord: String
)
The corresponding form.jsp
file might look like this:
<form:form>
<table>
<tr>
<td>Subscribe to newsletter?:</td>
<%-- Approach 1: The property is of type java.lang.Boolean --%>
<td><form:checkbox path="preferences.receiveNewsletter"/></td>
</tr>
<tr>
<td>Interests:</td>
<%-- Approach 2: The property is an array or has 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: The property is of type java.lang.Object --%>
<td>
Magic: <form:checkbox path="preferences.favouriteWord" value="Magic"/>
</td>
</tr>
</table>
</form:form>
There are three approaches to the checkbox
tag that should suit all your checkbox needs.
Approach one: If the associated value is of type
java.lang.Boolean
,input(checkbox)
is marked aschecked
if the associated value istrue
. Thevalue
attribute corresponds to the allowed value of thesetValue(Object)
value property.Approach two: If the associated value is of type
array
orjava.util.Collection
,input(checkbox)
is marked aschecked
if the configured value issetValue(Object)
is present in the associatedCollection
.Approach three: In case of any other type of associated value
input(checkbox)
is marked aschecked
if the configuredsetValue(Object)
is equal to the associated value.
Note that Regardless of the approach, the same HTML structure is generated. The following HTML snippet defines several 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>
You might not expect to see an extra hidden field after each checkbox. If a checkbox on an HTML page is not
checked, its value is not sent to the server as part of the HTTP request parameters after the form is submitted, so
a workaround for this HTML feature is needed in order for Spring form data binding to work. The
checkbox
tag follows the existing Spring convention of including a hidden parameter prefixed with an
underscore (_
) for each checkbox. By doing this, you are effectively telling Spring that "the checkbox
was visible on the form, and I want my object that the form data is bound to reflect the state of the checkbox,
no matter what."
The checkboxes
tag
This tag renders multiple HTML input
tags with type
set to checkbox
.
This section builds on the example from the
previous section about the checkbox
tag. Sometimes it is preferable not to list all possible hobbies on
a JSP page. It's better to specify a list of available options at runtime and pass it to the tag. This is the
purpose of the checkboxes
tag. You can pass a Array
, List
, or
Map
containing the available options in the items
property. Typically, the bound property
is a collection so that it can contain multiple values selected by the user. The following example shows a JSP page
that uses this tag:
<form:form>
<table>
<tr>
<td>Interests:</td>
<td>
<%-- Property is an array or is of type java.util.Collection --%>
<form:checkboxes path="preferences.interests" items="${interestList}"/>
</td>
</tr>
</table>
</form:form>
This example assumes that interestList
is a List
, available as a model attribute
that contains strings of values to select from. If you use Map
, the key of the Map entry is used as the
value, and the value of the Map entry is used as the label to display. You can also use a custom object in which you
can specify property names for the value using itemValue
and the label using itemLabel
.
The radiobutton
tag
This tag renders an HTML input
element with
type
set to radio
.
A typical usage involves multiple instances of tags bound to the same property but with different values, as shown in the following example:
<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 several input
HTML elements with
type
set to radio
.
As with the >checkboxes
tag, you can pass available
options as a runtime variable. To do this, you can use the radiobuttons
tag. You pass a
Array
, List
, or Map
containing the available options in the
items
property. If you use Map, the Map entry's key is used as the value and the Map entry's value is
used as the label to be displayed. You can also use a custom object where you can specify property names for a value
using itemValue
and a label using itemLabel
, as shown in the following example:
<tr>
<td>Sex:</td>
<td><form:radiobuttons path="sex" items="${sexOptions}"/></td>
</tr>
The password
tag
This tag renders the HTML input
tag with type set
to password
, with value bound.
<tr>
<td>Password:</td>
<td>
<form:password path="password"/>
</td>
</tr>
Please note that by default the password value is not shown. If you want the password value to be shown, you
can set the value of the showPassword
attribute to true
, as shown in the following
example:
<tr>
<td>Password:</td>
<td>
<form:password path="password" value="^76525bvHGq" showPassword="true"/>
</td>
</tr>>
The select
tag
This tag renders the "select" HTML element. It supports data binding to
the selected option, as well as the use of nested option
and options
tags.
Assume
that User
there is a list of skills. The corresponding HTML might look like this:
<tr>
<td>Skills:</td>
<td><form:select path="skills" items="${skills}"/></td>
</tr>
If User
has herbology skills, then the HTML source for the "Skills" string might look like this:
<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 the option
HTML element. It sets
selected
based on the associated value. The following HTML shows typical output for it:
<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 User
's house is in Gryffindor, then the HTML source for the string "House" will look like as
follows:
<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>
- Note the addition of the
selected
attribute.
The options
tag
This tag renders a list of HTML option
elements. It sets the
selected
attribute based on the associated value. The following HTML shows typical output for it:
<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 User
lived in the UK, the HTML source for the "Country" string would look like this:
<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>
- Note the addition of the
selected
attribute.
As shown in the previous example, combining the option
tag with the options
tag
produces the same standard HTML, but allows you to explicitly specify the value in JSP, which is intended only for
display (where it belongs), as in the case of the default string in the example: "-- Please Select".
The
items
usually populated with a collection or array of data item objects. itemValue
and
itemLabel
refer to the bean properties of these item objects, if specified. Otherwise, the item objects
themselves become strings. Alternatively, you can specify a Map
of elements, in which case the Map keys
will be interpreted as option values, and the Map values will correspond to option labels. If itemValue
or itemLabel
(or both) are also specified, then the data item's value property will be applied to the
Map key, and the data item's label property will be applied to the Map value.
The textarea
tag
This tag renders the textarea
HTML element. The following HTML shows the typical output for
it:
<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 the HTML input
tag with type
set to hidden
, with a value bound. To send an unbound hidden value, use the input
HTML tag
with type
set to hidden
. The following HTML shows the typical output for it:
<form:hidden path="house"/>
If you decide to pass the value of house
as hidden, then the HTML will look like this:
<input name="house" type="hidden" value="Gryffindor"/>
The errors
tag
This tag renders field errors in the HTML span
element. It
provides access to errors thrown in your controller or errors that were thrown by any validators associated with
your controller.
Suppose we want to display all error messages for the firstName
fields and
lastName
after submitting the form. We have a validator for instances of the User
class
called UserValidator
, as shown in the following example:
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.");
}
}
class UserValidator : Validator {
override fun supports(candidate: Class<*>): Boolean {
return User::class.java.isAssignableFrom(candidate)
}
override fun validate(obj: Any, errors: Errors) {
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "required", "Field is required.")
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "lastName", "required", "Field is required.")
}
}
form.jsp
might look like this:
<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,
then the HTML will look like this:
<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 following example shows that the
errors
tag also supports some basic substitution functionality.
path="*"
: Outputs to display all errors.path="lastName"
: Displays all errors associated with thelastName
field.If
path
is omitted, only object errors are printed.
In the following example, in A list of errors is displayed at the top of the page, and next to the fields there are errors specific to each field:
<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>
HTML will 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>
The spring-form.tld
tag library descriptor (TLD) is included in spring-webmvc.jar
.
For comprehensive information on individual tags, see API reference or refer to the tag library description.
Translating HTTP methods
Key principle REST is the use of a "unified interface". This means that all resources (URLs) can be
manipulated using the same four HTTP methods: GET, PUT, POST and DELETE. For each method, the HTTP specification
defines the exact semantics. For example, GET should always be a safe operation, meaning it has no side effects, and
PUT or DELETE should be idempotent, meaning you can repeat these operations over and over again, but the end result
should be the same. Although HTTP defines these four methods, HTML only supports two of them: GET and POST. Luckily,
there are two possible workarounds: you can either use JavaScript to do a PUT or DELETE, or you can do a POST with a
"real" method as an additional parameter (much like a hidden input field in an HTML form). Spring's HiddenHttpMethodFilter
takes advantage of this last trick. This filter is a regular servlet filter, so it can be used in conjunction with
any web framework (not just Spring MVC). Add this filter to your web.xml and a POST with a hidden
method
parameter will be converted to a request for the corresponding HTTP method.
In order to convert HTTP methods, the Spring MVC form tag has been updated in order to provide support for setting the HTTP method. For example, the following snippet is taken from the Pet Clinic example:
<form:form method="delete">
<p class="submit"><input type="submit" value="Delete Pet"/></p>
</form:form>
The previous example executes the HTTP POST method, while the "real" DELETE method is hidden behind a request
parameter. It is picked up by the HiddenHttpMethodFilter
, which is defined in web.xml, as shown in the
following example:
<filter>
<filter-name>httpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>httpMethodFilter</filter-name>
<servlet-name>petclinic</servlet-name>
</filter-mapping>
The following example shows the corresponding method with the @Controller
annotation:
@RequestMapping(method = RequestMethod.DELETE)
public String deletePet(@PathVariable int ownerId, @PathVariable int petId) {
this.clinic.deletePet(petId);
return "redirect:/owners/" + ownerId;
}
@RequestMapping(method = [RequestMethod.DELETE])
fun deletePet(@PathVariable ownerId: Int, @PathVariable petId: Int): String {
clinic.deletePet(petId)
return "redirect:/owners/$ownerId"
}
HTML5 tags
The Spring form tag library allows dynamic attribute input, which means you can enter any HTML5-specific attributes.
The input
form tag supports type attribute input , different from text
. This allows you
to visualize new HTML5-specific input types such as email
, date
, range
and others. Note that entering type='text'
is not required because text
is the default
type.