1. 程式人生 > >springMVC中jsp-form標籤使用總結

springMVC中jsp-form標籤使用總結

13.9. 使用Spring的表單標籤庫


從2.0開始,Spring提供全面的,支援資料繫結的JSP標籤來處理表單元素(如果你使用JSP和Spring的Web MVC框架的話)。 每個標籤所支援的屬性跟其對應的HTML標籤相同,這樣這些標籤看起來就不陌生,而且很容易用。 由這些標籤庫生成的HTML頁面符合HTML 4.01/XHTML 1.0標準。


與其它的標籤庫不同,Spring的表單標籤庫和Spring Web MVC框架是整合在一起的,因此它們可以直接使用命令物件(command object) 和其他由控制器處理的資料物件。 就像下面這些例子展示的一樣,使用這些標籤後,JSP 開發變得更加容易,程式碼也更加容易閱讀和維護。



讓我們通過例子來研究一下這些標籤是怎樣使用的。 在下面的例子中,當某個標籤的含義不夠明顯時,我們把它所生成的HTML程式碼也一起列了出來。
13.9.1. 配置標籤庫


Spring的表單標籤庫存在spring.jar中。這個庫的描述檔案(descriptor)是 spring-form.tld。


如果你想使用這些標籤, 請在JSP程式碼的起始部分加入下面這行宣告。


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


在上面的宣告中, form 是這個標籤庫所提供標籤的字首名。
13.9.2. form標籤



這個標籤會生成HTML form標籤,同時為form內部所包含的標籤提供一個繫結路徑(binding path)。 它把命令物件(command object)存在PageContext中,這樣form內部的標籤 就可以使用這個物件了。標籤庫中的其他標籤都宣告在form標籤的內部。


讓我們假設有一個叫User的領域物件,它是一個JavaBean,有著諸如 firstName和lastName這樣的屬性。我們將把它當作 一個表單支援物件(form backing object),它對應的表單控制器用 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="3">
                <input type="submit" value="Save Changes" />
            </td>
        </tr>
    </table>
</form:form>


上面例子中的firstName和lastName由控制器從 存在PageContext中的命令物件中得到。 下面幾個更復雜的例子展示了form內部標籤的用法。


這是由form標籤所生成的HTML程式碼,和標準的HTML form沒有什麼區別:


<form method="POST">
    <table>
      <tr>
          <td>First Name:</td>
          <td><input name="firstName" type="text" value="Harry"/></td>
          <td></td>
      </tr>
      <tr>
          <td>Last Name:</td>
          <td><input name="lastName" type="text" value="Potter"/></td>
          <td></td>
      </tr>
      <tr>
          <td colspan="3">
            <input type="submit" value="Save Changes" />
          </td>
      </tr>
    </table>
</form>


上面這個例子有一個隱藏的前提:表單支援物件(form backing object)的變數名是command。 如果你將這個物件用其他名稱加以定義(這可算是一種最佳實踐),你就可以將這個變數名繫結到表單上,如下例所示。


<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="3">
                <input type="submit" value="Save Changes" />
            </td>
        </tr>
    </table>
</form:form>


13.9.3. input標籤


這個標籤生成text型別的HTML input標籤。使用這個標籤時,path屬性的值將對應 HTML input標籤中name屬性的值。第 13.9.2 節 “form標籤”這一節中 有關於這個標籤的例子。
13.9.4. checkbox標籤


這個標籤生成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>
            <%-- Approach 1: Property is of type java.lang.Boolean --%>
            <td><form:checkbox path="preferences.receiveNewsletter"/></td>
            <td></td>
        </tr>


        <tr>
            <td>Interests:</td>
            <td>
                <%-- Approach 2: Property is of an array or of type java.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>
            <td></td>
        </tr>
        <tr>
            <td>Favourite Word:</td>
            <td>
                <%-- Approach 3: Property is of type java.lang.Object --%>
                Magic: <form:checkbox path="preferences.favouriteWord" value="Magic"/>
            </td>
            <td></td>
        </tr>
    </table>
</form:form>


checkbox有三種使用方法,應該可以滿足我們全部可能的需求。


    *


      第一種用法:若繫結值是java.lang.Boolean型別,則值為true時,input(checkbox)標為checked(選中)。其value(值)屬性對應於setValue(Object)值屬性的解析值。
    *


      第二種用法:若繫結值是array(陣列)型別或java.util.Collection,則配置的setValue(Object)值出現在繫結的Collection中時,input(checkbox)標為checked(選中)。
    *


      第三種用法:若繫結值為其他型別,則當配置的setValue(Object)等於其繫結值時,input(checkbox)標為checked(選中)。 


不管使用那一種方法,生成的HTML程式碼都是一樣的。下文是帶有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>
    <td></td>
</tr>


也許你注意到了每個checkbox元素後面都跟著一個隱藏區域(hidden field)。當一個HTML頁面中的checkbox沒有被選中時,這個checkbox的值不會在表單提交時作為HTTP請求引數傳送到伺服器端。這給Spring的表單資料繫結造成了麻煩。解決方法就是在每個 checkbox後面加一個隱藏區域,並且每個隱藏區域的名字是在其對應的checkbox名字前加下劃線("_")。這是Spring已有的慣例。這樣一來,你相當於告訴Spring“這個表單中存在這樣一個checkbox,我希望表單支援物件中相對應的屬性和這個checkbox的狀態保持一致 ”。
13.9.5. radiobutton標籤


這個標籤生成型別為radio的HTML input 標籤。


這個標籤的典型用法是一次宣告多個標籤例項,所有的標籤都有相同的path屬性,但是他們的value屬性不同。


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


13.9.6. password標籤


這個標籤生成型別為password的HTML input標籤。input標籤的值和表單支援物件相應屬性的值保持一致。


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


13.9.7. select標籤


這個標籤生成HTML select標籤。在生成的HTML程式碼中,被選中的選項和表單支援物件相應屬性的值保持一致。這個標籤也支援巢狀的option和options標籤。


在下面的例子中,我們假設User可以選擇自己的專業技能(多項選擇):


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


如果某個User的專業是草藥學(Herbology),生成的HTML程式碼就會像下面這樣:


<tr>
    <td>Skills:</td>
    <td><select name="skills" multiple="true">
        <option value="Potions">Potions</option>
        <option value="Herbology" selected="true">Herbology</option>
        <option value="Quidditch">Quidditch</option></select></td>
    <td></td>
</tr>


13.9.8. option標籤


這個標籤生成HTML option標籤。在生成的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的宿舍是Gryffindor,生成的HTML程式碼就會像下面這樣:


<tr>
    <td>House:</td>
    <td>
        <select name="house">
            <option value="Gryffindor" selected="true">Gryffindor</option>
            <option value="Hufflepuff">Hufflepuff</option>
            <option value="Ravenclaw">Ravenclaw</option>
            <option value="Slytherin">Slytherin</option>
        </select>
    </td>
 </tr>


譯者注:這一節中的幾個例子都跟《哈里波特》這本小說的內容有關。
13.9.9. 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>
    <td></td>
</tr>


如果某個User住在英國,生成的HTML程式碼就會像下面這樣:


 <tr>
    <td>Country:</td>
    <tr>
        <td>Country:</td>
        <td>
            <select name="country">
                <option value="-">--Please Select</option>
                <option value="AT">Austria</option>
                <option value="UK" selected="true">United Kingdom</option>
                <option value="US">United States</option>
            </select>
        </td>
        <td></td>
    </tr>
    <td></td>
</tr>


上面的這個例子同時使用了option標籤和options標籤。這兩個標籤生成的HTML程式碼是相同的,但是第一個option標籤允許你在JSP中明確宣告這個標籤的值只供顯示使用,並不繫結到表單支援物件的屬性上。
13.9.10. textarea標籤


這個標籤生成HTML textarea標籤。


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


13.9.11. hidden標籤


這個標籤生成型別為hidden的HTML input標籤。在生成的HTML程式碼中,input標籤的值和表單支援物件相應屬性的值保持一致。如果你需要宣告一個型別為hidden的input標籤,但是表單支援物件中沒有對應的屬性,你只能使用HTML的標籤。


<form:hidden path="house" />


上面的例子表示我們需要將house的值以隱含引數的形式提交,生成的HTML程式碼如下:


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


13.9.12. errors標籤


這個標籤生成型別為'span'的HTML標籤,用來顯示錶單驗證時出現的錯誤資訊。通過這個標籤,你可以訪問控制器(controller)和與控制器關聯的驗證器(validator)產生的錯誤資訊。


假設我們需要在表單提交時顯示所有跟firstName和lastName有關的錯誤資訊。我們為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>


如果我們提交表單時沒有填firstHame和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="*" - displays all errors


      path="*": 顯示所有的錯誤資訊
    *


      path="lastName*" - displays all errors associated with the lastName field


      path="lastName*": 顯示所有和lastName欄目有關的錯誤資訊。


下面這個例子在頁面的上方顯示所有的錯誤資訊,同時在表單每個欄目的旁邊顯示和該欄目有關的錯誤資訊。


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