You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
838 lines
26 KiB
838 lines
26 KiB
[[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 |
|
{api-spring-framework}/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",role="primary"] |
|
---- |
|
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",role="secondary"] |
|
---- |
|
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",role="primary"] |
|
---- |
|
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",role="secondary"] |
|
---- |
|
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 wildcarding 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 |
|
{api-spring-framework}/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",role="primary"] |
|
---- |
|
@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",role="secondary"] |
|
---- |
|
@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. |
|
|
|
|
|
|
|
|
|
|