概述 在低版本的Spring中,你必須經過JSTL或<spring:bind>將表單對象綁定到HTML表單頁面中,對於習慣了Struts表單標籤的開發者來講,Spring MVC的這一表現確實讓人失望。不過這一狀況已經一去不復返了,從Spring 2.0開始,Spring MVC開始全面支持表單標籤,經過Spring MVC表單標籤,咱們能夠很容易地將控制器相關的表單對象綁定到HTML表單元素中。 在本文中咱們將對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> 正由於表單頁面是經過訪問表單控制器導向過來的,因此<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表示表單元素髮生錯誤時對應的樣式,示例: 輸入組件標籤 表單中有一些用於接受輸入值的組件,如單行文本框、多行文本框以及密碼框,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> 你們可能已經注意到每一個複選框組件的後臺都跟着一個隱藏組件,這是由於當HTML頁面中的複選框沒有被選中時,這個複選框的值不會在表單提交時做爲HTTP請求參數發送到服務器端,這給Spring的表單數據綁定形成了麻煩——由於沒法觸發setFavorites()方法的調用(若是原來已經有值,這個值不會被設置爲空)。解決方法就是在每一個複選框後面加一個隱藏組件,而且將對應的複選框名字前添加一個下劃線("_")做爲隱藏組件的名字。這樣一來,你至關於告訴Spring「這個表單中存在這樣一個複選框,我但願表單對象中對應的屬性和這個checkbox的狀態保持一致」。 假設複選框對應的選項在數據庫或配置文件中定義,那麼頁面複選框標籤就不能經過硬編碼的方式指定,相反必須根據配置的選項數據動態產生。對於這樣的需求,代碼清單 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返回,最終將以屬性名值對方式出如今請求屬性中 return new ModelMap().addObject("favoriteMap", favoriteMap); } @Override protected ModelAndView onSubmit(Object command, BindException errors) throws Exception { User user = (User) command; bbtForum.registerUser(user); return new ModelAndView(getSuccessView(), "user", user); } }