JSP 和 JSTL

Spring Framework 具有用于将 Spring MVC 与 JSP 和 JSTL 一起使用的内置集成。

View 解析程序

使用 JSP 进行开发时,通常会声明InternalResourceViewResolver豆。

InternalResourceViewResolver可用于分派到任何 Servlet 资源,但在 特别是对于 JSP 来说。作为最佳实践,我们强烈建议将 JSP 文件放在 在'WEB-INF'目录中,因此客户端无法直接访问。

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

JSP 与 JSTL

使用 JSP 标准标记库 (JSTL) 时,必须使用特殊的视图类JstlView,因为 JSTL 需要先做一些准备,然后才能使用 I18N 功能 工作。

Spring 的 JSP 标记库

Spring 提供请求参数到命令对象的数据绑定,如 前面的章节。促进 JSP 页面的开发 data binding 功能,Spring 提供了一些标签,使事情变得更加容易。都 Spring 标签具有 HTML 转义功能,用于启用或禁用字符转义。

spring.tld标记库描述符 (TLD) 包含在spring-webmvc.jar. 有关各个标记的全面参考,请浏览 API 参考或查看标记库描述。

Spring 的表单标记库

从版本 2.0 开始, Spring 提供了一组全面的数据绑定感知标签,用于 在使用 JSP 和 Spring Web MVC 时处理表单元素。每个标签都支持 其对应的 HTML 标签对应的属性集,使标签 熟悉且直观易用。标记生成的 HTML 符合 HTML 4.01/XHTML 1.0 标准。

与其他表单/输入标记库不同, Spring 的表单标记库与 Spring Web MVC,为标签提供对命令对象和引用数据的 控制器处理。正如我们在以下示例中所示,表单标记使 JSP 更易于开发、阅读和维护。

我们将浏览 form 标记,并查看如何使用每个标记的示例。我们有 包含生成的 HTML 片段,其中某些标记需要进一步注释。

配置

表单标记库捆绑在spring-webmvc.jar.库描述符为 叫spring-form.tld.

要使用此库中的标记,请将以下指令添加到 JSP 的顶部 页:

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

哪里form是要用于此库中的标签的标签名称前缀。

表单标签

此标签呈现一个 HTML“form”元素,并公开一个指向内部标签的绑定路径 捆绑。它将命令对象放在PageContext以便 Command 对象可以 通过 inner 标签访问。此库中的所有其他标签都是form标记。

假设我们有一个名为User.它是一个具有属性 如firstNamelastName.我们可以将其用作 form 控制器,该控制器返回form.jsp.以下示例显示了form.jsp能 肖:

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

firstNamelastName值是从放置在 这PageContext通过页面控制器。继续阅读以查看更复杂的示例 如何将 inner 标记与form标记。

下面的清单显示了生成的 HTML,它看起来像一个标准表单:

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

前面的 JSP 假定表单支持对象的变量名称为command.如果您已将 form-backing 对象以其他名称放入模型中 (绝对是最佳实践),您可以将表单绑定到命名变量,因为 以下示例显示:

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

input标记

此标签呈现 HTMLinput元素,其绑定值和type='text'默认情况下。 有关此标记的示例,请参阅 Form 标记。您还可以使用 HTML5 特定的类型,例如email,tel,date等。

checkbox标记

此标签呈现 HTMLinput标签与type设置为checkbox.

假设我们的User具有首选项,例如新闻通讯订阅和 爱好。以下示例显示了Preferences类:

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;
	}
}

相应的form.jsp可能类似于以下内容:

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

有三种方法可以实现checkbox标签,它应该可以满足您的所有复选框需求。

  • 方法一:当绑定值为java.lang.Booleaninput(checkbox)标记为checked如果 bound 值为true.这value属性对应于setValue(Object)value 属性。

  • 方法二:当绑定值为arrayjava.util.Collectioninput(checkbox)标记为checked如果配置的setValue(Object)value 为 存在于 Bound 中Collection.

  • 方法三:对于任何其他绑定值类型,input(checkbox)标记为checked如果配置的setValue(Object)等于 bound 值。

请注意,无论采用哪种方法,都会生成相同的 HTML 结构。以下内容 HTML 代码段定义了一些复选框:

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

您可能不希望在每个复选框后看到额外的隐藏字段。 如果未选中 HTML 页面中的复选框,则其值不会发送到 server 作为 HTTP 请求参数的一部分,因此我们需要一个 HTML 中此怪癖的解决方法,以便 Spring 表单数据绑定正常工作。这checkbox标签遵循现有的 Spring 约定,即包含一个隐藏的参数 为每个复选框添加下划线 () 前缀。通过这样做,您可以有效地 告诉 Spring “复选框在表单中可见,我希望我的对象 无论如何,表单数据都会绑定以反映复选框的状态。_

checkboxes标记

此标签呈现多个 HTMLinput标签中带有type设置为checkbox.

本节基于前面的示例。checkboxtag 部分。有时,您更喜欢 不必在 JSP 页中列出所有可能的爱好。您宁愿提供 一个可用选项的列表,并将其传递给标签。那就是 目的checkboxes标记。您可以传入Array一个ListMap包含 的items财产。通常,绑定属性是 集合,以便它可以保存用户选择的多个值。以下示例 显示了使用此标记的 JSP:

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

此示例假定interestList是一个List可用作 Model 属性 ,其中包含要从中选择的值的字符串。如果您使用Map, 映射条目键用作值,映射条目的值用作 要显示的标签。您还可以使用自定义对象,您可以在其中提供 value 的属性名称itemValue和标签itemLabel.

radiobutton标记

此标签呈现 HTMLinput元素替换为type设置为radio.

典型的使用模式涉及绑定到同一属性的多个标记实例 但具有不同的值,如下例所示:

<tr>
	<td>Sex:</td>
	<td>
		Male: <form:radiobutton path="sex" value="M"/> <br/>
		Female: <form:radiobutton path="sex" value="F"/>
	</td>
</tr>

radiobuttons标记

此标签呈现多个 HTMLinput元素替换为type设置为radio.

checkboxes标记,您可能希望 将 available options 作为运行时变量传入。对于此用法,您可以使用radiobuttons标记。您传入一个Array一个ListMap,其中包含 的items财产。如果您使用Map,则映射入口键为 used as the value 和 map entry 的值用作要显示的标签。 您还可以使用自定义对象,您可以在其中为值提供属性名称 通过使用itemValue和标签itemLabel,如下例所示:

<tr>
	<td>Sex:</td>
	<td><form:radiobuttons path="sex" items="${sexOptions}"/></td>
</tr>

password标记

此标签呈现 HTMLinput标记中,并将类型设置为password替换为绑定值。

<tr>
	<td>Password:</td>
	<td>
		<form:password path="password"/>
	</td>
</tr>

请注意,默认情况下,不会显示 password 值。如果您确实希望使用 password 值,则可以设置showPassword属性设置为true,如下例所示:

<tr>
	<td>Password:</td>
	<td>
		<form:password path="password" value="^76525bvHGq" showPassword="true"/>
	</td>
</tr>

select标记

此标签呈现 HTML 'select' 元素。它支持将数据绑定到选定的 选项以及使用嵌套的optionoptions标签。

假设User有一个技能列表。相应的 HTML 可能如下所示:

<tr>
	<td>Skills:</td>
	<td><form:select path="skills" items="${skills}"/></td>
</tr>

如果User’sskill 在 Herbology 中,则 'Skills' 行的 HTML 源可以是 如下:

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

option标记

此标签呈现 HTMLoption元素。它设置selected,基于边界 价值。以下 HTML 显示了它的典型输出:

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

如果User’shouse 位于格兰芬多中,则 'House' 行的 HTML 源将为 如下:

<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 请注意,添加了selected属性。

options标记

此标签呈现 HTMLoption元素。它将selected属性 基于 Bound 值。以下 HTML 显示了它的典型输出:

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

如果User居住在英国,则“Country”行的 HTML 源如下所示:

<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 请注意,添加了selected属性。

如前面的示例所示,option标签与options标记 生成相同的标准 HTML,但允许您在 仅用于显示(属于它的位置)的 JSP,例如 示例:“-- 请选择”。

items属性通常填充 item 对象的集合或数组。itemValueitemLabel引用这些 Item 对象的 bean 属性,如果 指定。否则,item 对象本身将转换为字符串。或者 您可以指定Mapof items,在这种情况下,映射键被解释为 option values 和 map 值对应于选项标签。如果itemValueitemLabel(或两者兼而有之) 恰好也被指定,则 item 值属性适用于 map 键,并且 item label 属性适用于 map 值。

textarea标记

此标签呈现 HTMLtextarea元素。以下 HTML 显示了它的典型输出:

<tr>
	<td>Notes:</td>
	<td><form:textarea path="notes" rows="3" cols="20"/></td>
	<td><form:errors path="notes"/></td>
</tr>

hidden标记

此标签呈现 HTMLinput标签与type设置为hidden替换为绑定值。提交 未绑定的隐藏值,请使用 HTMLinput标签与type设置为hidden. 以下 HTML 显示了它的典型输出:

<form:hidden path="house"/>

如果我们选择提交house值设置为隐藏值,则 HTML 将如下所示:

<input name="house" type="hidden" value="Gryffindor"/>

errors标记

此标签在 HTML 中呈现字段错误span元素。它提供对错误的访问 在您的控制器中创建的,或者是由与 您的控制器。

假设我们想要显示firstNamelastName字段。我们有一个 Validator 用于User类 叫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.");
	}
}

form.jsp可能如下所示:

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

如果我们提交的表单在firstNamelastName领域 HTML 将如下所示:

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

如果我们想显示给定页面的整个错误列表怎么办?下一个例子 显示errors标签还支持一些基本的通配符功能。

以下示例在页面顶部显示错误列表,后跟 字段旁边的特定于字段的错误:

<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 将如下所示:

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

spring-form.tld标记库描述符 (TLD) 包含在spring-webmvc.jar. 有关各个标记的全面参考,请浏览 API 参考或查看标记库描述。

HTTP 方法转换

REST 的一个关键原则是使用“统一接口”。这意味着所有 可以使用相同的四种 HTTP 方法作资源 (URL):GET、PUT、POST、 和 DELETE 的 DELETE 命令。对于每种方法,HTTP 规范定义了确切的语义。为 例如,GET 应该始终是一个安全的作,这意味着它没有副作用, PUT 或 DELETE 应该是幂等的,这意味着您可以重复这些作 一遍又一遍,但最终结果应该是相同的。虽然 HTTP 定义了这些 四种方法,HTML 只支持两种:GET 和 POST。幸运的是,有两种可能 解决方法:您可以使用 JavaScript 执行 PUT 或 DELETE,也可以执行 POST 使用 “real” 方法作为附加参数(建模为 HTML 表单)。Spring的HiddenHttpMethodFilter使用后一个技巧。这 filter 是一个普通的 Servlet 过滤器,因此,它可以与任何 Web 框架(不仅仅是 Spring MVC)。将此过滤器添加到您的 web.xml,然后 POST 带有隐藏的methodparameter 转换为对应的 HTTP 方法 请求。

为了支持 HTTP 方法转换,更新了 Spring MVC 表单标记以支持设置 HTTP 方法。例如,以下代码片段来自 Pet Clinic 示例:

<form:form method="delete">
	<p class="submit"><input type="submit" value="Delete Pet"/></p>
</form:form>

前面的示例执行 HTTP POST,其中隐藏了 “真正的” DELETE 方法 请求参数。它由HiddenHttpMethodFilter,它在 web.xml,如下例所示:

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

以下示例显示了相应的@Controller方法:

@RequestMapping(method = RequestMethod.DELETE)
public String deletePet(@PathVariable int ownerId, @PathVariable int petId) {
	this.clinic.deletePet(petId);
	return "redirect:/owners/" + ownerId;
}

HTML5 标签

Spring 表单标签库允许输入动态属性,这意味着您可以 输入任何特定于 HTML5 的属性。

表单input标签支持输入 type 属性,而不是text.这是 旨在允许呈现新的 HTML5 特定输入类型,例如email,date,range等。请注意,输入type='text'不是必需的,因为text是默认类型。


APP信息