JSP和JSTL
Spring框架有一个内置的集成,用于将Spring MVC与JSP和JSTL结合使用。
1) View解析器
使用jsp开发时,可以声明InternalResourceViewResolver
或ResourceBundleViewResolver
bean。
ResourceBundleViewResolver
依赖于properties文件来定义映射到类和URL的视图名称。使用ResourceBundleViewResolver可以只使用一个解析器来混合不同类型的视图,如下例所示:
<bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver"> <property name="basename" value="views"/>bean># 使用一个简单的属性文件(view.properties在WEB-INF/classes中)welcome.(class)=org.springframework.web.servlet.view.JstlViewwelcome.url=/WEB-INF/jsp/welcome.jspproductList.(class)=org.springframework.web.servlet.view.JstlViewproductList.url=/WEB-INF/jsp/productlist.jsp
InternalResourceViewResolver
也可用于JSP。建议将你的JSP文件放在'WEB-INF'目录下的一个目录中,这样客户端就不能直接访问。
"viewResolver" "viewClass" "prefix" "suffix"
2) JSP与JSTL相比
当使用JSP标准标记库(JSTL)时,必须使用一个特殊的视图类JstlView,因为JSTL需要在I18N特性工作之前做一些准备。
3)Spring的JSP标记库
Spring提供请求参数到命令对象的数据绑定,为了结合这些数据绑定特性来促进JSP页面的开发,Spring提供了一些使事情变得更加简单的标记。所有Spring标记都具有HTML转义功能,可以启用或禁用字符转义。
spring.tld标记库描述符(TLD)包含在spring-webmvc.jar。org.springframework.web.servlet.tags包含Spring用于JSP 2.0+的JSP标准标记库。支持Spring的Web MVC框架中的JSP视图实现。
tag接口概要:
tag类概要:
示例:
<spring:hasBindErrors name="priceIncrease"><b>Please fix all errors!b>spring:hasBindErrors>
详细的使用和WEB.XML、JSP中配置网上有很多资料就再赘述。
4)Spring的表单标记库
从版本2.0开始,Spring提供了一组全面的数据绑定标记,用于在使用JSP和Spring Web MVC时处理表单元素。每个标记都为其对应的HTML标记对应项的属性集提供支持,使标记熟悉并易于使用。标记生成的HTML符合HTML 4.01/XHTML 1.0。
与其他form/input标记库不同,Spring的表单标记库与Spring Web MVC集成,允许标记访问控制器处理的命令对象和引用数据。如下面的示例所示,表单标记使jsp更易于开发、阅读和维护。
我们浏览表单标记,并查看如何使用每个标记的示例。我们已经包含了生成的HTML片段,其中某些标记需要进一步的注释。
a) 配置
表单标记库在spring-webmvc.jar。 库描述符称为spring-form.tld。
要使用此库中的标记,请在JSP页面顶部添加以下指令:
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
其中form
是要用于此库中标记的标记名前缀。
b)表单标记
此标记呈现HTML“form”元素,并向内部标记公开绑定路径进行绑定。它将command对象放在PageContext
中,以便内部标记可以访问command对象。此库中的所有其他标记都是form
标记的嵌套标记。
假设我们有一个名为User的对象。它是一个JavaBean,具有firstName
和lastName等属性。我们可以使用它作为表单控制器的表单备份对象,它返回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。如果已将表单备份对象以另一个名称放入model中,则可以将表单绑定到命名变量,如下例所示:
<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>
c) input 标签
此标记呈现一个HTML input
元素,默认情况下为绑定值,type='text'。有关此标记的示例,还可以使用HTML5特定的类型,如email
, tel
, date
和其他类型。
d)checkbox
标签
此标记呈现type
设置为checkbox的HTML input
标记。
假设我们的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> <%-- 方法1:属性为类型java.lang.Boolean --%> <td><form:checkbox path="preferences.receiveNewsletter"/>td> tr> <tr> <td>Interests:td> <%-- 方法2:属性是数组或类型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> <%-- 方法3:属性是java.lang.Object对象 --%> <td> Magic: <form:checkbox path="preferences.favouriteWord" value="Magic"/> td> tr> table>form:form>
checkbox
标记有三种方法,它们应该满足所有checkbox
需求。
方法一:当绑定值为类型时java.lang.Boolean,如果绑定值为true,则input(checkbox)标记为
checked
。value
属性对应于setValue(Object) value属性的解析值。方法二:当绑定值为
array
或java.util.Collection,如果绑定Collection中存在配置的setValue(Object)值,则input(checkbox)标记为checked
。方法三:对于任何其他绑定值类型,如果配置的setValue(Object)等于绑定值,则将input(checkbox)标记为
checked
。
注意,不管采用什么方法,都会生成相同的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页面中的复选框未选中,则在表单提交后,其值不会作为HTTP请求参数的一部分发送到服务器,因此我们需要一个HTML中的解决方案,以便Spring表单数据绑定工作。checkbox
标记遵循现有的Spring约定,即为每个复选框包含一个以_为前缀的隐藏参数。通过这样做,你可以有效地告诉Spring“复选框在表单中是可见的,我希望表单数据绑定到的对象反映复选框的状态,不管是什么。”
e) checkboxes 标记
此标记呈现多个type
设置为checkbox的HTML input
标记。
本节以上一个checkbox
标记部分的示例为基础。有时不希望在JSP页面中列出所有可能的爱好。宁愿在运行时提供可用选项的列表并将其传递给标记。这就是checkboxes
标记的目的。可以传入一个Array、List或Map
,其中包含items
属性中的可用选项。通常,绑定属性是一个集合,以便它可以保存用户选择的多个值。下面的示例显示了使用此标记的JSP:
<form:form> <table> <tr> <td>Interests:td> <td> <%--属性为数组或类型java.util.Collection --%> <form:checkboxes path="preferences.interests" items="${interestList}"/> td> tr> table>form:form>
本例假设interestList
是一个可用作model属性的List
,其中包含要从中选择的值的字符串。如果使用Map,则使用Map条目键作为值,并使用Map条目的值作为要显示的标签。还可以使用自定义对象,在该对象中,可以使用itemValue
提供值的属性名,使用itemLabel提供标签。
f) radiobutton 标签
此标记呈现type
设置为radio的HTML input
元素。
典型的使用模式涉及绑定到同一属性但具有不同值的多个标记实例,如下例所示:
<tr> <td>Sex:td> <td> Male: <form:radiobutton path="sex" value="M"/> <br/> Female: <form:radiobutton path="sex" value="F"/> td>tr>
g) radiobuttons 标签
此标记呈现多个type
设置为radio的HTML input
元素。
与checkboxes
标记一样,希望将可用选项作为运行时变量传入。对于这种用法,可以使用radiobuttons
标记。传入一个Array、List或Map
,其中包含items
属性中的可用选项。如果使用Map
,则使用Map
条目键作为值,使用Map
条目的值作为要显示的标签。还可以使用自定义对象,在该对象中,可以使用itemValue
提供值的属性名,并使用itemLabel提供标签,如下例所示:
<tr> <td>Sex:td> <td><form:radiobuttons path="sex" items="${sexOptions}"/>td>tr>
h) password 标签
此标记呈现一个HTML input
标记,类型设置为password
。
<tr> <td>Password:td> <td> <form:password path="password"/> td>tr>
请注意,默认情况下,不会显示密码值。如果确实要显示密码值,可以将showPassword
属性的值设置为true,如下例所示:
<tr> <td>Password:td> <td> <form:password path="password" value="^76525bvHGq" showPassword="true"/> td>tr>
I) select 标签
此标记呈现HTML“select”元素。它支持数据绑定到选定的选项,以及使用嵌套的option
和option
标记。
假设User
有一个技能列表。相应的HTML可以如下所示:
<tr> <td>Skills:td> <td><form:select path="skills" items="${skills}"/>td>tr>
如果用户的技能是Herbology,“skill s”行的HTML源代码如下:
<tr> <td>Skills:td> <td> <select name="skills" multiple="true"> <option value="Potions">Potionsoption> <option value="Herbology" selected="selected">Herbologyoption> <option value="Quidditch">Quidditchoption> select> td>tr>
K)option 标签
此标记呈现HTML选项元素。它基于绑定值设置选定项。下面的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>
如果用户的房子是Gryffindor,“house”行的HTML源代码如下:
<tr> <td>House:td> <td> <select name="house"> <option value="Gryffindor" selected="selected">Gryffindoroption> <option value="Hufflepuff">Hufflepuffoption> <option value="Ravenclaw">Ravenclawoption> <option value="Slytherin">Slytherinoption> select> td>tr>
L) options 标签
此标记呈现HTML option
元素的列表。它基于绑定值设置选定属性。下面的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>
如果用户居住在UK,则“Country”行的HTML源代码如下:
<tr> <td>Country:td> <td> <select name="country"> <option value="-">--Please Selectoption> <option value="AT">Austriaoption> <option value="UK" selected="selected">United Kingdomoption> <option value="US">United Statesoption> select> td>tr>
上例所示,将option标记与options标记结合使用将生成相同的标准HTML,但允许在JSP中显式指定一个仅用于显示(它所属的位置)的值,例如示例中的默认字符串:“--Please Select”。
items
属性通常由item对象的集合或数组填充。itemValue
和itemLabel
引用那些item对象的bean属性(如果指定的话)。否则,项对象本身将变成字符串。或者,可以指定项的Map
,在这种情况下,Map
键被解释为选项值,映射值对应于选项标签。如果同时指定了itemLabel
或itemValue
(或两者),则itemValue
属性将应用于映射键,itemLabel
属性将应用于映射值。
M) textarea
标签
此标记呈现HTML textarea
元素。下面的HTML显示了它的典型输出:
<tr> <td>Notes:td> <td><form:textarea path="notes" rows="3" cols="20"/>td> <td><form:errors path="notes"/>td>tr>
N) hidden
标签
此标记呈现一个HTML input
标记,其type
设置为hidden
。若要提交未绑定的hidden
,请使用类型设置为“hidden
”的HTML input
标记。下面的HTML显示了它的典型输出:
<form:hidden path="house"/>
如果我们选择将house
值作为hidden 值提交,则HTML将如下所示:
"house" type="hidden" value="Gryffindor"/>
O) errors
标签
此标记呈现HTML span
元素中的字段错误。它提供对在控制器中创建的错误或由与控制器关联的任何验证器创建的错误的访问。
假设我们希望在提交表单后显示firstName
和lastName
字段的所有错误消息。我们有一个名为UserValidator的
User
类实例的验证器,如下例所示:
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>
如果我们提交的表单在firstName
和lastName
字段中的值为空,则HTML将如下所示:
<form method="POST"> <table> <tr> <td>First Name:td> <td><input name="firstName" type="text" value=""/>td> <%-- 显示与firstName字段关联的错误 --%> <td><span name="firstName.errors">Field is required.span>td> tr> <tr> <td>Last Name:td> <td><input name="lastName" type="text" value=""/>td> <%-- 显示的与lastName字段关联的错误 --%> <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>
P)HTTP方法转换
REST的一个关键原则是使用“统一接口”。这意味着所有资源(url)都可以通过使用相同的四个HTTP方法进行操作:GET、PUT、POST和DELETE。对于每个方法,HTTP规范定义了确切的语义。例如,GET应该始终是一个安全的操作,这意味着它没有问题,PUT或DELETE应该是等幂的,这意味着可以一遍又一遍地重复这些操作,但最终的结果应该是相同的。虽然HTTP定义了这四种方法,但是HTML只支持两种:GET和POST。幸运的是,有两种可能的解决方法:可以使用JavaScript来执行PUT或DELETE,或者使用“real”方法作为附加参数(在HTML表单中建模为hidden 的输入字段)来完成POST。Spring的HiddenHttpMethodFilter
使用后一种技巧。这个过滤器是一个简单的Servlet过滤器,因此,它可以与任何web框架(不仅仅是Spring MVC)结合使用。将filter添加到web.xml文件,带有隐藏method
参数的POST将转换为相应的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,在请求参数后面hidden “real”DELETE方法。它由HiddenHttpMethodFilter获取,在web.xml文件,如下例所示:
<filter> <filter-name>httpMethodFilterfilter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilterfilter-class>filter><filter-mapping> <filter-name>httpMethodFilterfilter-name> <servlet-name>petclinicservlet-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;}
Q)HTML5标签
Spring表单标记库允许输入动态属性,也可以输入任何特定于HTML5的属性。
表单input
标记支持输入text以外的类型属性。这是为了允许呈现新的HTML5特定的输入类型,如email
, date
, range
和其他。请注意,输入type='text'不是必需的,因为text
是默认类型。
明天讲view 技术 Tiles等。
敬请持续关注。
欢迎关注和转发Spring中文社区(加微信群,可以关注后加我微信):