?
本文檔使用 PHP中文網(wǎng)手冊 發(fā)布
從2.0版本開始,如果使用JSP和Spring Web MVC的話,Spring提供了一套支持?jǐn)?shù)據(jù)綁定的標(biāo)簽集合,用于處理表單元素。 每個標(biāo)簽所支持的屬性集合和與其對應(yīng)的HTML標(biāo)簽相同,這就讓這些標(biāo)簽看起來很熟悉,而且用起來很直觀。 由這些標(biāo)簽庫生成的HTML頁面符合HTML 4.01/XHTML 1.0標(biāo)準(zhǔn)。
與其它表單/輸入標(biāo)簽庫不同,Spring的表單標(biāo)簽庫與Spring Web MVC集成在一起, 使標(biāo)簽可以使用命令對象(command object)和你的控制器處理的參考數(shù)據(jù)(reference data)。 就像下面這些例子展示的一樣,表單標(biāo)簽讓JSP更易于開發(fā)、閱讀和維護(hù)。
讓我們進(jìn)入表單標(biāo)簽的領(lǐng)域,并通過一個例子研究每個標(biāo)簽如何使用。 當(dāng)某些標(biāo)簽需要更進(jìn)一步的解釋時,我們已經(jīng)把所生成的HTML片段也一起列了進(jìn)來。
Spring的表單標(biāo)簽庫包含在spring.jar
中。
這個庫的描述符(descriptor)叫做spring-form.tld
。
要使用這個庫中的標(biāo)簽,在JSP頁面的開頭加入下面聲明:
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
在上面的聲明中,form
就是為想要使用的這個庫中的標(biāo)簽所確定的標(biāo)簽命名前綴。
這個標(biāo)簽會生成一個HTML的“form”標(biāo)簽,同時為內(nèi)部標(biāo)簽的綁定暴露了一個綁定路徑(binding path)。
它把命令對象(command object)放在PageContext
中,這樣內(nèi)部的標(biāo)簽就可以訪問這個命令對象了。
這個庫中的其他標(biāo)簽都是form
標(biāo)簽的嵌套標(biāo)簽。
假設(shè)我們有一個叫做User
的領(lǐng)域?qū)ο?,它是一個JavaBean,
擁有諸如firstName
和lastName
這樣的屬性。
我們將把它當(dāng)作返回form.jsp
的表單控制器的表單支持對象(form backing object)。
下面是一個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
中的命令對象中得到的。
請繼續(xù)讀下去來看幾個關(guān)于如何使用form
標(biāo)簽的內(nèi)部標(biāo)簽的例子。
生成的HTML看起來就是一個標(biāo)準(zhǔn)的form:
<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有一個預(yù)設(shè)前提,就是表單支持對象(form backing)的變量名是“command
”。
如果你將這個表單支持對象用其他名稱加以定義(這可算是一種最佳實(shí)踐),你就可以將這個命名變量綁定到表單上,如下例所示:
<form:form commandName="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>
這個標(biāo)簽生成一個“text”類型的HTML“input”標(biāo)簽。
關(guān)于這個標(biāo)簽的示例,請見第?13.9.2?節(jié) “form
標(biāo)簽”。
這個標(biāo)簽生成一個“checkbox”類型的HTML“input”標(biāo)簽。
讓我們假設(shè)我們的User
有比如新聞訂閱和其他一組業(yè)余愛好這樣的偏好。
下面就是一個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 typejava.lang.Boolean
--%> <td><form:checkbox path="preferences.receiveNewsletter"/></td> </tr> <tr> <td>Interests:</td> <td> <%-- Approach 2: Property is of an array or of typejava.util.Collection
--%> 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> <td> <%-- Approach 3: Property is of typejava.lang.Object
--%> Magic: <form:checkbox path="preferences.favouriteWord" value="Magic"/> </td> </tr> </table> </form:form>
有三種checkbox
標(biāo)簽的使用方法滿足你對checkbox的需求。
第一種用法:若綁定值是java.lang.Boolean
類型,則值為true
時,input(checkbox)
就標(biāo)記為選中。其value
屬性對應(yīng)于setValue(Object)
值的屬性的解析值。
第二種用法:若綁定值是array
或java.util.Collection
類型,則當(dāng)設(shè)定的setValue(Object)
值出現(xiàn)在綁定的Collection
中時,input(checkbox)
就標(biāo)記為選中。
第三種用法:若綁定值為其他類型,則當(dāng)設(shè)定的setValue(Object)
與其綁定值相等時,input(checkbox)
才標(biāo)記為選中。
注意,不管使用哪種方法,生成的HTML結(jié)構(gòu)都是相同的。下面是包含一些checkbox的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>
也許沒有注意到的是在每個checkbox背后還隱藏了其他字段(field)。
當(dāng)一個HTML頁面中的checkbox沒有被選中時,它的值不會在表單提交時作為HTTP請求參數(shù)的一部分發(fā)送到服務(wù)器端,
因此我們需要給這個HTML的奇怪動作想出一個變通方案,來讓Spring的表單數(shù)據(jù)綁定可以工作。
checkbox
標(biāo)簽遵循了Spring現(xiàn)有的慣例,就是對于每個checkbox都包含了一個下劃線("_"),再跟上一個隱藏參數(shù)。
這樣一來,就相當(dāng)于告訴Spring“
這個checkbox在表單中是可見的,并且希望表單數(shù)據(jù)將要被綁定到的對象能夠反映出任意的checkbox的狀態(tài)”。
這個標(biāo)簽生成多個“checkbox”類型的HTML“input”標(biāo)簽。
這一節(jié)建立在上一節(jié)checkbox
標(biāo)簽的例子之上。
有時傾向于并不在JSP頁面中列出全部可能的業(yè)余愛好,而是想在運(yùn)行時提供一個可用選項(xiàng)的清單,并把它傳遞給相應(yīng)標(biāo)簽。
這就是checkboxes
標(biāo)簽的目標(biāo)。
傳入一個Array
、List
,或者Map
,
并把可用選項(xiàng)包含在“items”屬性中。典型的情況是,這個綁定的屬性是一個集合,這樣它才能持有用戶選擇的多個值。
下面是使用了這個標(biāo)簽的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
的情況下,map條目的鍵被用作值,map條目的值被用作顯示的文本標(biāo)記。
也可以使用一個定制的對象,提供“itemValue”屬性存放值,“itemLabel”屬性存放文本標(biāo)記。
這個標(biāo)簽生成一個“radio”類型的HTML“input”標(biāo)簽。
一個典型用法是把多個標(biāo)簽實(shí)例綁定到同一屬性上,但它們有不同的值。
<tr> <td>Sex:</td> <td>Male: <form:radiobutton path="sex" value="M"/> <br/> Female: <form:radiobutton path="sex" value="F"/> </td> </tr>
這個標(biāo)簽生成多個“radio”類型的HTML“input”標(biāo)簽。
正像上面提到的checkboxes
標(biāo)簽,你可能希望傳入一個運(yùn)行時的變量作為可用的選項(xiàng)。
這種用法下就需要使用radiobuttons
標(biāo)簽。
傳入一個Array
、List
,或者Map
,
并把可用選項(xiàng)包含在“items”屬性中。在使用Map
的情況下,map條目的鍵被用作值,
map條目的值被用作顯示的文本標(biāo)記。也可以使用一個定制的對象,提供“itemValue”屬性存放值,“itemLabel”屬性存放文本標(biāo)記。
<tr> <td>Sex:</td> <td><form:radiobuttons path="sex" items="${sexOptions}"/></td> </tr>
這個標(biāo)簽生成一個“password”類型的HTML“input”標(biāo)簽,并賦以綁定的值。
<tr> <td>Password:</td> <td> <form:password path="password" /> </td> </tr>
請注意默認(rèn)情況下,口令的值不會被顯示出來。
如果一定要顯示口令的值,就把“showPassword
”屬性的值置為true。
<tr> <td>Password:</td> <td> <form:password path="password" value="^76525bvHGq" showPassword="true" /> </td> </tr>
這個標(biāo)簽生成一個HTML“select”元素。它支持被選中的選項(xiàng)的數(shù)據(jù)綁定,
也支持使用嵌套的option
和options
標(biāo)簽。
我們假設(shè)有一個User
擁有多項(xiàng)專長。
<tr> <td>Skills:</td> <td><form:select path="skills" items="${skills}"/></td> </tr>
如果這個User
的專長是草藥學(xué),那么“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>
這個標(biāo)簽生成一個HTML的“option”。根據(jù)綁定的值,它會恰當(dāng)?shù)脑O(shè)置“selected”屬性。
<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
的宿舍在Gryffindor(Gryffindor是哈利?波特在Hogwarts的宿舍――譯者注),
那么“House”這一行的HTML源代碼就如下所示:
<tr> <td>House:</td> <td> <select name="house"> <option value="Gryffindor" selected="selected">Gryffindor</option> <option value="Hufflepuff">Hufflepuff</option> <option value="Ravenclaw">Ravenclaw</option> <option value="Slytherin">Slytherin</option> </select> </td> </tr>
這個標(biāo)簽生成一個HTML的“option”標(biāo)簽的列表。根據(jù)綁定的值,它會恰當(dāng)?shù)脑O(shè)置“selected”屬性。
<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> <option value="US">United States</option> </select> </td> </tr>
上面的例子展示了結(jié)合使用option
標(biāo)簽和options
標(biāo)簽產(chǎn)生相同的標(biāo)準(zhǔn)HTML,
也讓你在JSP中顯式的指定一個值只用于顯示目的(在它所處的位置),例如例子中的默認(rèn)字符串:“--Please Select”。
這個標(biāo)簽生成一個HTML的“textarea”。
<tr> <td>Notes:</td> <td><form:textarea path="notes" rows="3" cols="20" /></td> <td><form:errors path="notes" /></td> </tr>
這個標(biāo)簽使用綁定的值生成類型為“hidden”的HTML“input”標(biāo)簽。
在生成的HTML代碼中,input標(biāo)簽的值和表單支持對象相應(yīng)屬性的值保持一致。
如果要提交一個未綁定的值,就只能使用類型為“hidden”的HTML input
標(biāo)簽了。
<form:hidden path="house" />
如果我們選擇以隱藏形式提交“house”的值,HTML代碼將如下所示:
<input name="house" type="hidden" value="Gryffindor"/>
這個標(biāo)簽通過一個HTML“span”標(biāo)簽展現(xiàn)字段的錯誤。它提供了訪問由你的控制器或者與你的控制器關(guān)聯(lián)的任何驗(yàn)證器產(chǎn)生的錯誤的途徑。
假設(shè)我們想要在表單提交時顯示所有與firstName
和lastName
字段有關(guān)的錯誤。
我們?yōu)?code class="classname">User類的實(shí)例編寫了名為UserValidator
的驗(yàn)證器。
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> <%-- 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
標(biāo)簽也支持一些基本的通配符功能。
path="*"
:顯示所有錯誤
path="lastName*"
:顯示所有與lastName
字段有關(guān)的錯誤
下面的例子將會在頁面頭部顯示一個錯誤清單,后面則在每個字段旁邊顯示該字段特有的錯誤:
<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> </form>