839 lines
26 KiB
Plaintext
839 lines
26 KiB
Plaintext
[[mvc-view-jsp]]
|
|
= JSP and JSTL
|
|
|
|
The Spring Framework has a built-in integration for using Spring MVC with JSP and JSTL.
|
|
|
|
|
|
|
|
[[mvc-view-jsp-resolver]]
|
|
== View Resolvers
|
|
|
|
When developing with JSPs, you typically declare an `InternalResourceViewResolver` bean.
|
|
|
|
`InternalResourceViewResolver` can be used for dispatching to any Servlet resource but in
|
|
particular for JSPs. As a best practice, we strongly encourage placing your JSP files in
|
|
a directory under the `'WEB-INF'` directory so there can be no direct access by clients.
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<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>
|
|
----
|
|
|
|
|
|
|
|
[[mvc-view-jsp-jstl]]
|
|
== JSPs versus JSTL
|
|
|
|
When using the JSP Standard Tag Library (JSTL) you must use a special view class, the
|
|
`JstlView`, as JSTL needs some preparation before things such as the I18N features can
|
|
work.
|
|
|
|
|
|
|
|
[[mvc-view-jsp-tags]]
|
|
== Spring's JSP Tag Library
|
|
|
|
Spring provides data binding of request parameters to command objects, as described in
|
|
earlier chapters. To facilitate the development of JSP pages in combination with those
|
|
data binding features, Spring provides a few tags that make things even easier. All
|
|
Spring tags have HTML escaping features to enable or disable escaping of characters.
|
|
|
|
The `spring.tld` tag library descriptor (TLD) is included in the `spring-webmvc.jar`.
|
|
For a comprehensive reference on individual tags, browse the
|
|
{spring-framework-api}/web/servlet/tags/package-summary.html#package.description[API reference]
|
|
or see the tag library description.
|
|
|
|
|
|
[[mvc-view-jsp-formtaglib]]
|
|
== Spring's form tag library
|
|
|
|
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.
|
|
|
|
Unlike other form/input tag libraries, Spring's form tag library is integrated with
|
|
Spring Web MVC, giving the tags access to the command object and reference data your
|
|
controller deals with. As we show in the following examples, the form tags make
|
|
JSPs easier to develop, read, and maintain.
|
|
|
|
We go through the 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.
|
|
|
|
|
|
[[mvc-view-jsp-formtaglib-configuration]]
|
|
=== Configuration
|
|
|
|
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:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
|
|
----
|
|
where `form` is the tag name prefix you want to use for the tags from this library.
|
|
|
|
|
|
[[mvc-view-jsp-formtaglib-formtag]]
|
|
=== The Form Tag
|
|
|
|
This tag renders an HTML 'form' element 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.
|
|
|
|
Assume that we have a domain object called `User`. It is a JavaBean with properties
|
|
such as `firstName` and `lastName`. We can use it as the form-backing object of our
|
|
form controller, which returns `form.jsp`. The following example shows what `form.jsp` could
|
|
look like:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<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. Keep reading to see more complex examples of
|
|
how inner tags are used with the `form` tag.
|
|
|
|
The following listing shows the generated HTML, which looks like a standard form:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<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 preceding JSP assumes that the variable name of the form-backing object is
|
|
`command`. If you have put the form-backing object into the model under another name
|
|
(definitely a best practice), you can bind the form to the named variable, as the
|
|
following example shows:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<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>
|
|
----
|
|
|
|
|
|
[[mvc-view-jsp-formtaglib-inputtag]]
|
|
=== The `input` Tag
|
|
|
|
This tag renders an HTML `input` element with the bound value and `type='text'` by default.
|
|
For an example of this tag, see xref:web/webmvc-view/mvc-jsp.adoc#mvc-view-jsp-formtaglib-formtag[The Form Tag]. You can also use
|
|
HTML5-specific types, such as `email`, `tel`, `date`, and others.
|
|
|
|
|
|
[[mvc-view-jsp-formtaglib-checkboxtag]]
|
|
=== The `checkbox` Tag
|
|
|
|
This tag renders an HTML `input` tag with the `type` set to `checkbox`.
|
|
|
|
Assume that our `User` has preferences such as newsletter subscription and a list of
|
|
hobbies. The following example shows the `Preferences` class:
|
|
|
|
[tabs]
|
|
======
|
|
Java::
|
|
+
|
|
[source,java,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
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;
|
|
}
|
|
}
|
|
----
|
|
|
|
Kotlin::
|
|
+
|
|
[source,kotlin,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
class Preferences(
|
|
var receiveNewsletter: Boolean,
|
|
var interests: StringArray,
|
|
var favouriteWord: String
|
|
)
|
|
----
|
|
======
|
|
|
|
The corresponding `form.jsp` could then resemble the following:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<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 three approaches to the `checkbox` tag, which should meet all your checkbox needs.
|
|
|
|
* 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.
|
|
* 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`.
|
|
* 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. The following
|
|
HTML snippet defines some checkboxes:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<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 the additional hidden field after each checkbox.
|
|
When a checkbox in an HTML page is not checked, its value is not sent to the
|
|
server as part of the HTTP request parameters once the form is submitted, so we need a
|
|
workaround for this quirk in HTML for Spring form data binding to work. The
|
|
`checkbox` tag follows the existing Spring convention of including a hidden parameter
|
|
prefixed by an underscore (`_`) for each checkbox. By doing this, you are effectively
|
|
telling Spring that "`the checkbox was visible in the form, and I want my object to
|
|
which the form data binds to reflect the state of the checkbox, no matter what.`"
|
|
|
|
|
|
[[mvc-view-jsp-formtaglib-checkboxestag]]
|
|
=== The `checkboxes` Tag
|
|
|
|
This tag renders multiple HTML `input` tags with the `type` set to `checkbox`.
|
|
|
|
This section build on the example from the previous `checkbox` tag section. Sometimes, you prefer
|
|
not to have to list all the possible hobbies in your JSP page. You would rather provide
|
|
a list at runtime of the available options and pass that in to the tag. That is the
|
|
purpose of the `checkboxes` tag. You can pass in an `Array`, a `List`, or a `Map` that contains
|
|
the available options in the `items` property. Typically, the bound property is a
|
|
collection so that it can hold multiple values selected by the user. The following example
|
|
shows a JSP that uses this tag:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<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 example assumes that the `interestList` is a `List` available as a model attribute
|
|
that contains strings of the values to be selected from. If you use a `Map`,
|
|
the map entry 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 provide the
|
|
property names for the value by using `itemValue` and the label by using `itemLabel`.
|
|
|
|
|
|
|
|
[[mvc-view-jsp-formtaglib-radiobuttontag]]
|
|
=== The `radiobutton` Tag
|
|
|
|
This tag renders an HTML `input` element with the `type` set to `radio`.
|
|
|
|
A typical usage pattern involves multiple tag instances bound to the same property
|
|
but with different values, as the following example shows:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<tr>
|
|
<td>Sex:</td>
|
|
<td>
|
|
Male: <form:radiobutton path="sex" value="M"/> <br/>
|
|
Female: <form:radiobutton path="sex" value="F"/>
|
|
</td>
|
|
</tr>
|
|
----
|
|
|
|
|
|
[[mvc-view-jsp-formtaglib-radiobuttonstag]]
|
|
=== The `radiobuttons` Tag
|
|
|
|
This tag renders multiple HTML `input` elements with the `type` set to `radio`.
|
|
|
|
As with the xref:web/webmvc-view/mvc-jsp.adoc#mvc-view-jsp-formtaglib-checkboxestag[`checkboxes` tag], you might want to
|
|
pass in the available options as a runtime variable. For this usage, you can use the
|
|
`radiobuttons` tag. You pass in an `Array`, a `List`, or a `Map` that contains the
|
|
available options in the `items` property. If you use a `Map`, the map entry key is
|
|
used as the value and the map entry's value are used as the label to be displayed.
|
|
You can also use a custom object where you can provide the property names for the value
|
|
by using `itemValue` and the label by using `itemLabel`, as the following example shows:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<tr>
|
|
<td>Sex:</td>
|
|
<td><form:radiobuttons path="sex" items="${sexOptions}"/></td>
|
|
</tr>
|
|
----
|
|
|
|
|
|
[[mvc-view-jsp-formtaglib-passwordtag]]
|
|
=== The `password` Tag
|
|
|
|
This tag renders an HTML `input` tag with the type set to `password` with the bound value.
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<tr>
|
|
<td>Password:</td>
|
|
<td>
|
|
<form:password path="password"/>
|
|
</td>
|
|
</tr>
|
|
----
|
|
|
|
Note that, by default, the password value is not shown. If you do want the
|
|
password value to be shown, you can set the value of the `showPassword` attribute to
|
|
`true`, as the following example shows:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<tr>
|
|
<td>Password:</td>
|
|
<td>
|
|
<form:password path="password" value="^76525bvHGq" showPassword="true"/>
|
|
</td>
|
|
</tr>
|
|
----
|
|
|
|
|
|
[[mvc-view-jsp-formtaglib-selecttag]]
|
|
=== 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.
|
|
|
|
Assume that a `User` has a list of skills. The corresponding HTML could be as follows:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<tr>
|
|
<td>Skills:</td>
|
|
<td><form:select path="skills" items="${skills}"/></td>
|
|
</tr>
|
|
----
|
|
|
|
If the `User's` skill are in Herbology, the HTML source of the 'Skills' row could be
|
|
as follows:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<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>
|
|
----
|
|
|
|
|
|
[[mvc-view-jsp-formtaglib-optiontag]]
|
|
=== The `option` Tag
|
|
|
|
This tag renders an HTML `option` element. It sets `selected`, based on the bound
|
|
value. The following HTML shows typical output for it:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<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 be
|
|
as follows:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<tr>
|
|
<td>House:</td>
|
|
<td>
|
|
<select name="house">
|
|
<option value="Gryffindor" selected="selected">Gryffindor</option> <1>
|
|
<option value="Hufflepuff">Hufflepuff</option>
|
|
<option value="Ravenclaw">Ravenclaw</option>
|
|
<option value="Slytherin">Slytherin</option>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
----
|
|
<1> Note the addition of a `selected` attribute.
|
|
|
|
|
|
[[mvc-view-jsp-formtaglib-optionstag]]
|
|
=== The `options` Tag
|
|
|
|
This tag renders a list of HTML `option` elements. It sets the `selected` attribute,
|
|
based on the bound value. The following HTML shows typical output for it:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<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 be as follows:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<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> <1>
|
|
<option value="US">United States</option>
|
|
</select>
|
|
</td>
|
|
</tr>
|
|
----
|
|
<1> Note the addition of a `selected` attribute.
|
|
|
|
As the preceding example shows, the combined usage of an `option` tag with the `options` tag
|
|
generates the same standard HTML but lets you explicitly specify a value in the
|
|
JSP that is for display only (where it belongs), such as the default string in the
|
|
example: "-- Please Select".
|
|
|
|
The `items` attribute is typically populated with a collection or array of item objects.
|
|
`itemValue` and `itemLabel` refer to bean properties of those item objects, if
|
|
specified. Otherwise, the item objects themselves are turned into strings. Alternatively,
|
|
you can specify a `Map` of items, in which case the map keys are interpreted as option
|
|
values and the map values correspond to option labels. If `itemValue` or `itemLabel` (or both)
|
|
happen to be specified as well, the item value property applies to the map key, and
|
|
the item label property applies to the map value.
|
|
|
|
|
|
[[mvc-view-jsp-formtaglib-textareatag]]
|
|
=== The `textarea` Tag
|
|
|
|
This tag renders an HTML `textarea` element. The following HTML shows typical output for it:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<tr>
|
|
<td>Notes:</td>
|
|
<td><form:textarea path="notes" rows="3" cols="20"/></td>
|
|
<td><form:errors path="notes"/></td>
|
|
</tr>
|
|
----
|
|
|
|
|
|
[[mvc-view-jsp-formtaglib-hiddeninputtag]]
|
|
=== The `hidden` Tag
|
|
|
|
This tag renders an HTML `input` tag with the `type` set to `hidden` with the bound value. To submit
|
|
an unbound hidden value, use the HTML `input` tag with the `type` set to `hidden`.
|
|
The following HTML shows typical output for it:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<form:hidden path="house"/>
|
|
----
|
|
|
|
If we choose to submit the `house` value as a hidden one, the HTML would be as follows:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<input name="house" type="hidden" value="Gryffindor"/>
|
|
|
|
----
|
|
|
|
|
|
[[mvc-view-jsp-formtaglib-errorstag]]
|
|
=== The `errors` Tag
|
|
|
|
This tag renders field errors in an HTML `span` element. It provides access to the errors
|
|
created in your controller or those that were created by any validators associated with
|
|
your controller.
|
|
|
|
Assume that 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`, as the following example shows:
|
|
|
|
[tabs]
|
|
======
|
|
Java::
|
|
+
|
|
[source,java,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
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.");
|
|
}
|
|
}
|
|
----
|
|
|
|
Kotlin::
|
|
+
|
|
[source,kotlin,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
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.")
|
|
}
|
|
}
|
|
----
|
|
======
|
|
|
|
The `form.jsp` could be as follows:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<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,
|
|
the HTML would be as follows:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<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 next example
|
|
shows that the `errors` tag also supports some basic wildcard functionality.
|
|
|
|
* `path="{asterisk}"`: Displays all errors.
|
|
* `path="lastName"`: Displays all errors associated with the `lastName` field.
|
|
* If `path` is omitted, only object errors are displayed.
|
|
|
|
The following example displays a list of errors at the top of the page, followed by
|
|
field-specific errors next to the fields:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<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 be as follows:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<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 the `spring-webmvc.jar`.
|
|
For a comprehensive reference on individual tags, browse the
|
|
{spring-framework-api}/web/servlet/tags/form/package-summary.html#package.description[API reference]
|
|
or see the tag library description.
|
|
|
|
|
|
|
|
[[mvc-rest-method-conversion]]
|
|
=== HTTP Method Conversion
|
|
|
|
A key principle of REST is the use of the "`Uniform Interface`". This means that all
|
|
resources (URLs) can be manipulated by using the same four HTTP methods: GET, PUT, POST,
|
|
and DELETE. For each method, the HTTP specification defines the exact semantics. For
|
|
instance, a GET should always be a safe operation, meaning that it has no side effects,
|
|
and a PUT or DELETE should be idempotent, meaning that you can repeat these operations
|
|
over and over again, but the end result should be the same. While HTTP defines these
|
|
four methods, HTML only supports two: GET and POST. Fortunately, there are two possible
|
|
workarounds: you can either use JavaScript to do your PUT or DELETE, or you can do a POST
|
|
with the "`real`" method as an additional parameter (modeled as a hidden input field in an
|
|
HTML form). Spring's `HiddenHttpMethodFilter` uses this latter trick. This
|
|
filter is a plain Servlet filter and, therefore, it can be used in combination with any
|
|
web framework (not just Spring MVC). Add this filter to your web.xml, and a POST
|
|
with a hidden `method` parameter is converted into the corresponding HTTP method
|
|
request.
|
|
|
|
To support HTTP method conversion, the Spring MVC form tag was updated to support setting
|
|
the HTTP method. For example, the following snippet comes from the Pet Clinic sample:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<form:form method="delete">
|
|
<p class="submit"><input type="submit" value="Delete Pet"/></p>
|
|
</form:form>
|
|
----
|
|
|
|
The preceding example performs an HTTP POST, with the "`real`" DELETE method hidden behind
|
|
a request parameter. It is picked up by the `HiddenHttpMethodFilter`, which is defined in
|
|
web.xml, as the following example shows:
|
|
|
|
[source,xml,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
<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 `@Controller` method:
|
|
|
|
[tabs]
|
|
======
|
|
Java::
|
|
+
|
|
[source,java,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
@RequestMapping(method = RequestMethod.DELETE)
|
|
public String deletePet(@PathVariable int ownerId, @PathVariable int petId) {
|
|
this.clinic.deletePet(petId);
|
|
return "redirect:/owners/" + ownerId;
|
|
}
|
|
----
|
|
|
|
Kotlin::
|
|
+
|
|
[source,kotlin,indent=0,subs="verbatim,quotes"]
|
|
----
|
|
@RequestMapping(method = [RequestMethod.DELETE])
|
|
fun deletePet(@PathVariable ownerId: Int, @PathVariable petId: Int): String {
|
|
clinic.deletePet(petId)
|
|
return "redirect:/owners/$ownerId"
|
|
}
|
|
----
|
|
======
|
|
|
|
[[mvc-view-jsp-formtaglib-html5]]
|
|
=== HTML5 Tags
|
|
|
|
The Spring form tag library allows entering dynamic attributes, which means you can
|
|
enter any HTML5 specific attributes.
|
|
|
|
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.
|
|
|
|
|
|
|
|
|