此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Framework 6.2.10! |
JSP 和 JSTL
Spring Framework 具有内置的集成,用于将 Spring MVC 与 JSP 和 JSTL 一起使用。
查看解析器
使用 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>
Spring 的 JSP 标签库
Spring 提供请求参数与命令对象的数据绑定,如 前面的章节。促进 JSP 页面的开发与这些 数据绑定功能,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 更易于开发、阅读和维护。
我们浏览表单标签,并查看每个标签的使用方式示例。我们有 包括生成的 HTML 片段,其中某些标签需要进一步注释。
配置
表单标签库捆绑在spring-webmvc.jar
.库描述符是
叫spring-form.tld
.
要使用此库中的标记,请将以下指令添加到 JSP 的顶部 页:
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
哪里form
是要用于此库中的标记的标记名称前缀。
表单标签
此标签呈现 HTML 'form' 元素,并公开内部标签的绑定路径
捆绑。它将命令对象放在PageContext
以便命令对象可以
可通过内部标签访问。此库中的所有其他标签都是form
标记。
假设我们有一个名为User
.它是一个具有属性的 JavaBean
如firstName
和lastName
.我们可以将其用作
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>
这firstName
和lastName
从放置在
这PageContext
由页面控制器。继续阅读以查看更复杂的示例
内部标签如何与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: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'
默认情况下。
有关此标记的示例,请参阅表单标记。您还可以使用
HTML5 特定类型,例如email
,tel
,date
,等。
这checkbox
标记
此标签呈现 HTMLinput
标记与type
设置为checkbox
.
假设我们的User
具有首选项,例如时事通讯订阅和列表
爱好。以下示例显示了Preferences
类:
-
Java
-
Kotlin
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
)
相应的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.Boolean
这input(checkbox)
被标记为checked
如果绑定值为true
.这value
属性对应于setValue(Object)
value 属性。 -
方法二:当绑定值类型为
array
或java.util.Collection
这input(checkbox)
被标记为checked
如果配置的setValue(Object)
值为 存在于边界中Collection
. -
方法三:对于任何其他绑定值类型,使用
input(checkbox)
被标记为checked
如果配置的setValue(Object)
等于绑定值。
请注意,无论采用哪种方法,都会生成相同的 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
.
本节基于上一个示例构建checkbox
标签部分。有时,您更喜欢
不必在您的 JSP 页面中列出所有可能的爱好。您宁愿提供
运行时列出可用选项并将其传递给标签。那就是
目的checkboxes
标记。您可以传入Array
一个List
或Map
包含
中的可用选项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
可作为模型属性使用
包含要从中选择的值的字符串。如果您使用Map
,
映射条目键用作值,映射条目的值用作
要显示的标签。您还可以使用自定义对象,您可以在其中提供
属性名称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
标记,您可能想要
将可用选项作为运行时变量传入。对于这种用法,您可以使用radiobuttons
标记。你传入一个Array
一个List
或Map
其中包含
中的可用选项items
财产。如果您使用Map
,则地图入口键为
用作值,地图条目的值用作要显示的标签。
您还可以使用自定义对象,您可以在其中提供值的属性名称
通过使用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 值,您可以设置showPassword
属性设置为true
,如以下示例所示:
<tr>
<td>Password:</td>
<td>
<form:password path="password" value="^76525bvHGq" showPassword="true"/>
</td>
</tr>
这select
标记
此标签呈现 HTML 'select' 元素。它支持将数据绑定到所选的
选项以及嵌套option
和options
标签。
假设User
有一个技能清单。相应的 HTML 可能如下所示:
<tr>
<td>Skills:</td>
<td><form:select path="skills" items="${skills}"/></td>
</tr>
如果User’s
技能在草药学中,“技能”行的 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’s
house 位于格兰芬多,则“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
标记
此标签呈现 HTML 列表option
元素。它设置了selected
属性
基于绑定值。以下 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
居住在英国,则“国家/地区”行的 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
属性通常填充了项目对象的集合或数组。itemValue
和itemLabel
引用这些项目对象的 bean 属性,如果
指定。否则,项对象本身将转换为字符串。或者
您可以指定Map
项目,在这种情况下,映射键被解释为选项
值和映射值对应于选项标签。如果itemValue
或itemLabel
(或两者兼而有之)
恰好也指定了,item value 属性适用于 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
value 作为隐藏的,则 HTML 如下:
<input name="house" type="hidden" value="Gryffindor"/>
这errors
标记
此标记在 HTML 中呈现字段错误span
元素。它提供对错误的访问
在您的控制器中创建的,或由与
你的控制器。
假设我们想要显示firstName
和lastName
字段。我们有一个用于User
类
叫UserValidator
,如以下示例所示:
-
Java
-
Kotlin
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
可以如下:
<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>
如果我们提交的表单中值为空firstName
和lastName
领域
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
标签还支持一些基本的通配符功能。
-
path="*"
:显示所有错误。 -
path="lastName"
:显示与lastName
田。 -
如果
path
省略,则仅显示对象错误。
以下示例在页面顶部显示错误列表,后跟 字段旁边的特定字段错误:
<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。对于每种方法,HTTP 规范定义了确切的语义。为
例如,GET 应该始终是一个安全的作,这意味着它没有副作用,
PUT 或 DELETE 应该是幂等的,这意味着您可以重复这些作
一遍又一遍,但最终结果应该是一样的。虽然 HTTP 定义了这些
四种方法,HTML 只支持两种:GET 和 POST。幸运的是,有两种可能
解决方法:您可以使用 JavaScript 进行 PUT 或 DELETE,也可以执行 POST
使用“实数”方法作为附加参数(建模为
HTML 表单)。Spring的HiddenHttpMethodFilter
使用后一种技巧。这
filter 是一个普通的 Servlet 过滤器,因此,它可以与任何
Web 框架(不仅仅是 Spring MVC)。将此过滤器添加到您的web.xml,然后 POST
带有隐藏的method
参数转换为相应的 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
方法:
-
Java
-
Kotlin
@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"
}