天天看點

使用Spring MVC表單标(轉)

概述 

    在低版本的Spring中,你必須通過JSTL或<spring:bind>将表單對象綁定到HTML表單頁面中,對于習慣了Struts表單标簽的開發者來說,Spring MVC的這一表現确實讓人失望。不過這一情況已經一去不複返了,從Spring 2.0開始,Spring MVC開始全面支援表單标簽,通過Spring MVC表單标簽,我們可以很容易地将控制器相關的表單對象綁定到HTML表單元素中。 

在上一篇文章《Spring MVC的表單控制器》中(http://tech.it168.com/j/2007-07-26/200707261434046.shtml)我們已經使用到了部分的Spring MVC表單标簽,在本文中我們将對Spring MVC表單标簽進行全面的介紹,讓我們首先從<form.:form>标簽開始吧。 

form标簽 

    和使用任何JSP擴充标簽一樣,在使用Spring表單标簽之前,你必須在JSP頁面中添加一行引用Spring表單标簽的聲明,如下所示: 

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%><%@ taglib prefix="form"uri="http://www.springframework.org/tags/form"%> ①引入标簽的聲明 <html> … ②聲明後,在頁面中就可以使用任意Spring表單标簽了 </html>

    一般情況下,我們使用“form”作為Spring MVC表單标簽的字首,當然隻要願意,你可以調整為其它的字首名。在聲明好标簽引用後,就可以在該JSP檔案中使用所有Spring MVC的表單标簽了。下面是一個使用<form.:form>表單标簽的示例,它将最終生成一個HTML的 form表單:  

<form.:form> 使用者名:<form.:input path="userName"/><br> 密 碼:<form.:password path="password"/><br> Email:<form.:input path="email"/><br><input type="submit" value="注冊" name="testSubmit"/><input type="reset" value="重置"/></form.:form>

     回憶一下我們在《Spring MVC的表單控制器》(http://tech.it168.com/j/2007-07-26/200707261434046.shtml)文章中介紹的使用者系統資料庫單控制器,使用者通過GET請求調用表單控制器時,表單控制器生成一個新的表單對象,然後重定向到表單輸入頁面。正因為表單頁面是通過通路表單控制器導向過來的,是以<form.:form>标簽本身無需做額外的設定就可以達到以下兩個目标: 

    1) 它不需要象HTML的<form>标簽或Struts的表單标簽一樣通過action屬性指定表單送出的位址。假設和<form.:form>标簽對應的控制器的URL是“/registerUser.html”,應用部署目錄為“baobaotao”,則最後産生的HTML代碼自動包含表單送出位址: 

<form. id="command" method="post" action="/baobaotao//registerUser.html">…</form> 

    2) <form.:form>标簽内部的元件标簽(如<form.:input>、<form.:password>等)可以直接和表單控制器所對應的表單對象進行值綁定。 

    預設情況下,表單控制器将表單對象以“command”為名放到PageContext中,你可以通過表單控制器commandName屬性的設定使用其它的名字(假設設定為“user”),這時你必須通過<form.:form. commandName="user">顯式指定綁定的表單對象名稱。

    除了commandName屬性外,Spring表單标簽擁有豐富的可設定屬性,這些屬性大都是HTML表單标簽屬性的鏡像,如onclick、ondblclick、tabindex等等。需要注意的一點是這些屬性都是小寫的,而對應的HTML标簽的屬性則沒有這個限制。但是有幾個和HTML标簽有差別的屬性,我們通過表 1進行說明: 

    表 1 表單元素标簽特殊屬性

目錄

說明

cssClass

使用該屬性指定表單元素CSS樣式名,相當于HTML元素的class屬性。示例:<form.:input path="userName" cssClass="inputStyle"/>。

cssStyle

直接通過該屬性指定樣式,相當于HTML元素的style屬性。示例:

<form.:input path="userName" cssStyle="width:100px"/>。

cssErrorClass

cssClass表示表單元素未發生錯誤時對應的樣式,而cssErrorClass表示表單元素發生錯誤時對應的樣式,示例:

<form.:input path="userName" cssClass="sty1" cssErrorClass= "sty2"/>

輸入元件标簽 

    表單中有一些用于接受輸入值的元件,如單行文本框、多行文本框以及密碼框,Spring為它們提供了對應的表單标簽,請看下面的例子: 

代碼清單 1 使用輸入元件标簽的表單 

<form.:form> 使用者名:<form.:input path="userName"/><br> ①單行檔案框标簽密 碼:<form.:password path="password"/><br> ②密碼框标簽描 述:<form.:textarea path="desc" cols="20" rows="3"/><br> ③多行檔案框标簽 <form.:hidden path="times"/> ④隐藏元件的值 <input type="submit" value="注冊" name="testSubmit"/><input type="reset" value="重置"/></form.:form>

    正如你看到的,所有表單元件标簽都通過path屬性綁定表單對象的屬性值,它支援級聯屬性,比如path="user.userName"将調用表單對象getUser.getUserName()綁定表單對象的屬性值。這些表單元件标簽擁有大多數HTML元件标簽的鏡像屬性,如③處的<form.:textarea>就使用了cols和rows屬性設定列數和行數。 

以上使用表單标簽的頁面的對應HTML頁面如下所示:

<form. id="command" method="post" action="/baobaotao//registerUser.html"> 使用者名:<input id="userName" name="userName" type="text" value=""/><br> 密 碼: <input id="password" name="password" type="password" value=""/><br> 描 述:<textarea id="desc" name="desc" rows="3" cols="20"></textarea><br><input id="times" name="times" type="hidden" value="0"/><input type="submit" value="注冊" name="testSubmit"/><input type="reset" value="重置"/></form>

單選框和複選框元件标簽 

    單選框和複選框元件雖然在HTML中都對應<input>元素标簽,但在Spring MVC表單标簽中,它們分别對應兩個更達意的标簽:    

<form.:radiobutton>和<form.:checkbox>。 radiobutton 單選框元件由兩個同名的标簽元件組成,當表單對象對應屬性值和value值相等時,單選框選中。下面是一個代表性别的單選框: <form.:form> 性 别:<form.:radiobutton path="sex" value="0"/>男 <form.:radiobutton path="sex" value="1"/>女 </form.:form> 當表單對象的sex屬性為0時(可以是String、int等可以自動轉換為String的類型),所生成的HTML代碼如下所示: <form. id="command" method="post" action="/baobaotao//registerUser.html"> 性 别:<input id="sex1" name="sex" type="radio" value="0" checked="checked"/>男 <input id="sex2" name="sex" type="radio" value="1"/>女 </form> 

checkbox 

    複選框元件标簽相對來說複雜一些,複選框元件對應的表單屬性不但可以boolean類型,還可以是String[]、Collection,Enum等類型。針對不同屬性類型,複選框的選中狀态的判斷條件是不一樣的: 

 boolean類型:當對應屬性為true時,該複選框選中(一個屬性僅對應一個複選框); 

 String[]、Collection或Enum類型:複選框對應值出現在對應屬性清單中,該複選框選中; 

 其它類型:當複選框對應的值可以轉換為對應屬性值,該複選框選中。 

假設使用者注冊的User表單對象包含了一個List類型的favorites屬性: 

import java.util.List; 

public class User { 

private List favorites; 

public List getFavorites() { 

return favorites; 

public void setFavorites(List favorites) { 

this.favorites = favorites; 

我們希望将其在頁面中使用一個複選框元件綁定這個屬性,則可以使用以下的代碼: 

代碼清單 2 複選框标簽的使用 

<form.:form> 

興趣愛好: 

<form.:checkbox path="favorites" value="1"/>computer 

<form.:checkbox path="favorites" value="2"/>sport 

<form.:checkbox path="favorites" value="3"/>entertainment 

<form.:checkbox path="favorites" value="4"/>literature 

</form.:form> 

除了正常的path屬性名外,還必須提供一個value屬性,假設User表單對象的favorites屬性包括了1和3的值,那麼産生的HTML頁面為: 

<form. id="command" method="post" action="/baobaotao//registerUser.html"> 

興趣愛好:<input id="favorites1" name="favorites" type="checkbox" value="1" checked="checked"/> 

<input type="hidden" value="1" name="_favorites"/>computer 

<input id="favorites2" name="favorites" type="checkbox" value="2" /> 

<input type="hidden" value="1" name="_favorites"/>sport 

<input id="favorites3" name="favorites" type="checkbox" value="3" checked="checked"/> 

<input type="hidden" value="1" name="_favorites"/>entertainment 

<input id="favorites4" name="favorites" type="checkbox" value="4"/> 

<input type="hidden" value="1" name="_favorites"/>literature 

</form> 

假設複選框對應的選項在資料庫或配置檔案中定義,那麼頁面複選框标簽就不能通過寫死的方式指定,相反必須根據配置的選項資料動态産生。對于這樣的需求,代碼清單 2的編寫方式顯然不能滿足需求。回憶一下表單控制器的工作流程,我們知道可以通過複寫referenceData()方法在表單顯示前準備一些需要的資料,現在終于派上用場了,來看一下具體的實作: 

代碼清單 3 UserRegisterController:準備表單顯示資料

package com.baobaotao.web.user; … import org.springframework.ui.ModelMap; public class UserRegisterController extends SimpleFormController { private BbtForum bbtForum; ①建立初始表單對象 protected Object formBackingObject(HttpServletRequest request) throws Exception { int userId = ServletRequestUtils.getIntParameter(request, "userId",-1); User user = bbtForum.getUser(userId); user.setUserName("tom"); List favorites =new ArrayList();①-1預設選中值為1和3的選項 favorites.add("1"); favorites.add("3"); user.setFavorites(favorites); return user; } @Override ②準備表單顯示時需要的資料 protected Map referenceData(HttpServletRequest request) throws Exception { Map favoriteMap =new LinkedHashMap(); favoriteMap.put("1", "computer"); favoriteMap.put("2", "sport"); favoriteMap.put("3", "entertainment"); favoriteMap.put("4", "literature"); ②-1将表單頁面需要的對象以ModelMap傳回,最終将以屬性名值對方式出現在請求屬性中 returnnew ModelMap().addObject("favoriteMap", favoriteMap); } @Override protected ModelAndView onSubmit(Object command, BindException errors) throws Exception { User user = (User) command; bbtForum.registerUser(user); returnnew ModelAndView(getSuccessView(), "user", user); } }

    在以上代碼中我們覆寫了SimpleFormController的referenceData()和formBackingObject ()方法。參照《Spring MVC的表單控制器》中(http://tech.it168.com/j/2007-07-26/200707261434046.shtml)介紹的表單控制器工作流程,可以知道formBackingObject()方法用于表單頁面初始化時使用的表單對象。我們在formBackingObject()方法中,将User的favorites屬性的初始值設定為1和3(分别對應computer和entertainment的選項),如①所示。 

在②處,我們覆寫了referenceData()方法,該方法為表單頁面準備一些資料。該方法傳回值類型為Map,該Map的鍵值将會綁定到請求的屬性中。ModelMap是Spring 2.0新增的Map實作類,它提供了鍊式方法和預設鍵值的機制。這裡,我們使用ModelMap綁定了一個鍵為“favoriteMap”,值為favoriteMap的資料對象。favoriteMap是所有興趣愛好的選項,在實際的應用中,你可以從資料庫中或配置檔案中進行加載。 

當請求中綁定了favoriteMap時,對應的表單頁面就可以周遊該Map并動态構造出複選框清單了:   

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%><html><head><title>寶寶淘論壇使用者注冊</title></head><body><form.:form> … 興趣愛好: <c:forEach items="${favoriteMap}"var="favorite">①引用favoriteMap的請求屬性 ②引用Map的鍵和值 <form.:checkbox path="favorites" value="${favorite.key}"/>${favorite.value} </c:forEach><input type="submit" value="注冊" name="testSubmit"/><input type="reset" value="重置"/></form.:form></body></html>

    在①處,我們通過JSTL标簽對屬性名為favoriteMap的模型資料對象進行周遊,為每一個元素項生成一個複選框。注意②處的複選框代碼,它有兩個明顯的特征:1)使用Spring複選框标簽;2)通過EL引用Map類型的模型資料。由于favorite是Map類型,是以我們可以通過${favorite.key}和${favorite.value}引用Map元素的鍵和值。

    提示:

    對于同時使用JSTL和Spring表單标簽的JSP檔案,JSTL的标簽會被首先解析,然後再解析Spring表單标簽,是以如執行個體那樣混合使用二者可以如預期一樣輸出正确的結果。

下拉框元件标簽 

    下拉框标簽的典型形式為: <form.:select path="city" items="${cityList}"/>,它包括兩方面的資料:1)對應表單對象屬性值(city);2)用于構造整個下拉框選項的資料(cityList)。嚴格地說,下拉框元件分為單選和多選兩種形式,當表單對象對應屬性為複數形态的類型時(如String[]、List、Set),産生的目标元件為多選下拉框,反之為單選下拉框。 

用于構造下拉框選項的資料也必須在referenceData()方法中準備好(可能從資料庫字典表中加載或從外部配置檔案中加載): 

代碼清單 4 UserRegisterController:為下拉框标簽準備資料

package com.baobaotao.web.user; … public class UserRegisterController extends SimpleFormController { @Override protected Map referenceData(HttpServletRequest request) throws Exception { Map favoriteMap =new LinkedHashMap(); favoriteMap.put("1", "computer"); favoriteMap.put("2", "sport"); favoriteMap.put("3", "entertainment"); favoriteMap.put("4", "literature"); List cityList =new ArrayList();①為下拉框選項準備的資料 cityList.add("北京"); cityList.add("上海"); cityList.add("天津"); cityList.add("廈門"); returnnew ModelMap() .addObject("favoriteMap", favoriteMap) .addObject("cityList", cityList); } … } 這時,生成的下拉框HTML代碼如下所示: <select id="city" name="city"> ① <option value="北京">北京</option><option value="上海">上海</option><option value="天津">天津</option><option value="廈門">廈門</option></select><input type="hidden" name="_city" value="1"/> ②

    首先,我們注意到②處有一個和複選框元件相似的配套隐藏元件,之是以會需要這個隐藏元件是出于和複選框相同的原因。下拉框的值和标簽是相同的,都是cityList清單中的元素值。在實際應用中,我們一般為每一個選項提供一個代碼,而非采用和标簽相同的值,這樣可以使用規範簡短的代碼儲存資料,為後續的查詢、引用帶來友善。這時,可以采用下拉框标簽的另一種屬性設定方式: 

<form.:select path="city" items="${cityMap}" itemValue="key" itemLabel="value"/> 

cityMap是一個已經通過referenceData()方法準備好的Map對象,itemValue對應下拉框的value屬性,而itemValue="key"表示使用cityMap元素的鍵,itemLable對應下拉框的标簽值, itemLabel="value"表示使用cityMap元素的值。實際上,items屬性所綁定的也可以是一個List對象,其元素可以是一個JavaBean,這時可以通過itemValue和itemLabel指定引用JavaBean的屬性。如下所示: 

<form.:select path="city" items="${cities}" itemValue="code" itemLabel="name"/> 

cities對應一個通過referenceData()方法準備好的List對象,其元素為City對象,City對象包括code和name兩個屬性。通過以上這些方式,我們可以得到一個選項的值和标簽不相同的下拉框: 

<select id="city" name="city"> 

<option value="1">北京</option> 

<option value="2">上海</option> 

<option value="3">天津</option> 

<option value="4" >廈門</option> 

</select> 

<input type="hidden" name="_city" value="1"/> 

一般情況下,下拉框會提供一個類似于“請選擇”或“--未選擇--”的預設選項,這個選項本身不是有效的資料項,它們的存在僅僅為提示使用者作選擇或代表一個未作選擇的空值。這時,我們可能會考慮手工提供一個下拉框選項,而其它的選項通過referenceData()提供的資料動态生成: 

<form.:select path="city"> 

<form.:option value="" label="--請選擇--"/> ①提示性的選項 

<form.:options items="${cityMap}" itemValue="key" itemLabel="value"/>②真實的選項資料 

</form.:select> 

這樣産生的下拉框在預設情況下将顯示①處對應的選項,如果使用者沒有選擇,選項相當于是一個空值。②處對應的<form.:options>會将cityMap的資料轉換為下拉框選項清單。 

錯誤标簽 

    錯誤标簽是和服務端校驗資訊關聯的對應物,假設在服務端通過以下代碼對表單資料進行校驗: 

ValidationUtils.rejectIfEmptyOrWhitespace(errors, "userName","required.username", "使用者名必須填寫"); 

ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password","required.password", "密碼不能為空"); 

    當送出的表單資料不合法引發校驗錯誤時,送出的表單将被駁回,請求被重定向到表單輸入頁面,在該頁面中通過

<form.:errors>标簽就可以顯示出校驗的錯誤資訊: <form.:form> 使用者名:<form.:input path="userName" cssClass="inputStyle" cssErrorClass="asdfe"/><font color="red"><form.:errors path="userName"/></font><br> 密 碼:<form.:password path="password"/><font color="red"><form.:errors path="password"/></font><br></form.:form>

    通過path和表單對象特定屬性錯誤資訊進行綁定,一個表單對象屬性可能包括一個或多個錯誤資訊,也可以沒有錯誤資訊,<form.:errors>會根據錯誤資訊的情況進行合理的展示。此外,path還支援通配符比對的表示方式: 

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

 path="lastName*": 顯示所有屬性名字首為lastName的錯誤資訊。 

小結 

    在Spring 2.0中,新增的表單标簽是Spring MVC的一個顯著的更新,它可以綁定服務端的表單對象,讓頁面資料的渲染工作變得輕松。因為Spring MVC架構本身的優越性,使得許多Spring MVC表單标簽無需進行過多的屬性設定就可以正确使用,是以相比于Struts的表單标簽,Spring MVC在使用上更加友善,更加輕松。

本文轉自茄子_2008部落格園部落格,原文連結:http://www.cnblogs.com/xd502djj/p/3245491.html,如需轉載請自行聯系原作者。