对于最新的稳定版本,请使用 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 集成,使标签能够访问命令对象和引用数据controller 处理。正如我们在以下示例中所示,表单标签使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"
}