在使用SpringMVC的時候我們可以使用Spring封裝的一系列表單標籤,這些標籤都可以訪問到ModelMap中的內容。下面將對這些標籤一一介紹。
在正式介紹SpringMVC的表單標籤之前,我們需要先在JSP中聲明使用的標籤,具體做法是在JSP文件的頂部加入以下指令:
Jsp代碼
- <%@taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
1.1 form標籤
使用Spring的form標籤主要有兩個作用,第一是它會自動的綁定來自Model中的一個屬性值到當前form對應的實體對象,默認是command屬性,這樣我們就可以在form表單體裏面方便的使用該對象的屬性了;第二是它支持我們在提交表單的時候使用除GET和POST之外的其他方法進行提交,包括DELETE和PUT等。
1.1.1 支持綁定表單對象
我們先來看如下使用form標籤的一個示例:
Jsp代碼
- <form:form action="formTag/form.do" method="post">
- <table>
- <tr>
- <td>Name:</td><td><form:input path="name"/></td>
- </tr>
- <tr>
- <td>Age:</td><td><form:input path="age"/></td>
- </tr>
- <tr>
- <td colspan="2"><input type="submit" value="提交"/></td>
- </tr>
- </table>
- </form:form>
<form:form action="formTag/form.do" method="post">
<table>
<tr>
<td>Name:</td><td><form:input path="name"/></td>
</tr>
<tr>
<td>Age:</td><td><form:input path="age"/></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="提交"/></td>
</tr>
</table>
</form:form>
這個時候如果Model中存在一個屬性名稱爲command的javaBean,而且該javaBean擁有屬性name和age的時候,在渲染上面的代碼時就會取command的對應屬性值賦給對應標籤的值。如在上面的代碼中,假設Model中存在一個屬性名稱爲command的javaBean,且它的name和age屬性分別爲“Zhangsan”和“36”時,那麼它在渲染時就會生成如下一段代碼:
- <formid="command"action="formTag/form.do"method="post">
- <table>
- <tr>
- <td>Name:</td><td><inputid="name"name="name"type="text"value="ZhangSan"/></td>
- </tr>
- <tr>
- <td>Age:</td><td><inputid="age"name="age"type="text"value="36"/></td>
- </tr>
- <tr>
- <tdcolspan="2"><inputtype="submit"value="提交"/></td>
- </tr>
- </table>
- </form>
<form id="command" action="formTag/form.do" method="post">
<table>
<tr>
<td>Name:</td><td><input id="name" name="name" type="text" value="ZhangSan"/></td>
</tr>
<tr>
<td>Age:</td><td><input id="age" name="age" type="text" value="36"/></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="提交"/></td>
</tr>
</table>
</form>
從上面生成的代碼中,我們可以看出,當沒有指定form標籤的id時它會自動獲取該form標籤綁定的Model中對應屬性名稱作爲id,而對於input標籤在沒有指定id的情況下它會自動獲取path指定的屬性作爲id和name。
我們指定form默認自動綁定的是Model的command屬性值,那麼當我的form對象對應的屬性名稱不是command的時候,應該怎麼辦呢?對於這種情況,Spring給我們提供了一個commandName屬性,我們可以通過該屬性來指定我們將使用Model中的哪個屬性作爲form需要綁定的command對象。除了commandName屬性外,指定modelAttribute屬性也可以達到相同的效果。這裏假設上面代碼中我們存放在Model中的是user對象而不是默認的command對象,那麼我們的代碼就可以如下定義了:
- <form:form action="formTag/form.do" method="post" commandName="user">
- <table>
- <tr>
- <td>Name:</td><td><form:input path="name"/></td>
- </tr>
- <tr>
- <td>Age:</td><td><form:input path="age"/></td>
- </tr>
- <tr>
- <td colspan="2"><input type="submit" value="提交"/></td>
- </tr>
- </table>
- </form:form>
<form:form action="formTag/form.do" method="post" commandName="user">
<table>
<tr>
<td>Name:</td><td><form:input path="name"/></td>
</tr>
<tr>
<td>Age:</td><td><form:input path="age"/></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="提交"/></td>
</tr>
</table>
</form:form>
1.1.2 支持全部的Http請求方法
- <form:form action="formTag/form.do" method="delete" modelAttribute="user">
- <table>
- <tr>
- <td>Name:</td><td><form:input path="name"/></td>
- </tr>
- <tr>
- <td>Age:</td><td><form:input path="age"/></td>
- </tr>
- <tr>
- <td colspan="2"><input type="submit" value="提交"/></td>
- </tr>
- </table>
- </form:form>
<form:form action="formTag/form.do" method="delete" modelAttribute="user">
<table>
<tr>
<td>Name:</td><td><form:input path="name"/></td>
</tr>
<tr>
<td>Age:</td><td><form:input path="age"/></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="提交"/></td>
</tr>
</table>
</form:form>
在上面代碼中我們設定了該form的提交方法是delete,這樣在後臺我們就可以給對應的請求方法的RequestMapping加上method爲RequestMethod.DELETE的限制。我們來看一下上面的代碼在進行渲染的時候會生成怎樣的Html代碼,其生成的代碼如下所示:
- <formid="user"action="formTag/form.do"method="post">
- <inputtype="hidden"name="_method"value="delete"/>
- <table>
- <tr>
- <td>Name:</td><td><inputid="name"name="name"type="text"value="ZhangSan"/></td>
- </tr>
- <tr>
- <td>Age:</td><td><inputid="age"name="age"type="text"value="36"/></td>
- </tr>
- <tr>
- <tdcolspan="2"><inputtype="submit"value="提交"/></td>
- </tr>
- </table>
- </form>
<form id="user" action="formTag/form.do" method="post">
<input type="hidden" name="_method" value="delete"/>
<table>
<tr>
<td>Name:</td><td><input id="name" name="name" type="text" value="ZhangSan"/></td>
</tr>
<tr>
<td>Age:</td><td><input id="age" name="age" type="text" value="36"/></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="提交"/></td>
</tr>
</table>
</form>
從它生成的代碼我們可以看出,Spring在實現除GET和POST之外的請求方法時,還是使用的POST方法進行請求,然後給表單加上了一個隱藏域,用以表示真正的請求方法,這個隱藏域的名稱默認是“_method”。上面這樣定義之後是不是就意味着我們可以以delete方式訪問到“formTag/form.do”了呢?答案是不行的。這樣定義我們只是多加了一個用以表示請求方法的隱藏域而已,實際的請求方式還是POST。Spring爲我們提供了一個Filter——HiddenHttpMethodFilter,通過這個Filter我們可以把以POST方式傳遞過來的表示實際請求方式的參數轉換爲對應的真正的Http請求方法。所以這個時候我們還需要在web.xml中加上如下代碼:
- <filter>
- <filter-name>hiddenHttpMethodFilter</filter-name>
- <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>hiddenHttpMethodFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
注意:HiddenHttpMethodFilter只能對以POST方式進行傳遞的表示請求方式的隱藏域轉換爲真正的Http請求方式。當我們直接在form:form標籤的method中使用除GET和POST方法以外的其他方法時,Spring會自動生成以POST方式進行傳遞的表單以及對應的隱藏域。所以當我們需要手動的設置表示請求方法的隱藏域時,我們就需要指定表單的請求方式爲POST,爲GET將不會生效。
- <form:form action="formTag/form.do" method="post" modelAttribute="user">
- <input type="hidden" name="_method" value="head"/>
- <table>
- <tr>
- <td>Name:</td><td><form:input path="name"/></td>
- </tr>
- <tr>
- <td>Age:</td><td><form:input path="age"/></td>
- </tr>
- <tr>
- <td colspan="2"><input type="submit" value="提交"/></td>
- </tr>
- </table>
- </form:form>
<form:form action="formTag/form.do" method="post" modelAttribute="user">
<input type="hidden" name="_method" value="head"/>
<table>
<tr>
<td>Name:</td><td><form:input path="name"/></td>
</tr>
<tr>
<td>Age:</td><td><form:input path="age"/></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="提交"/></td>
</tr>
</table>
</form:form>
上面代碼就是一個手動定義請求方式的隱藏域的示例。這裏表示請求方式的隱藏域的名稱默認是“_method”,如果不想使用這個默認值的話,我們也可以通過form:form標籤的methodParam屬性來指定。如下面這個示例:
- <form:form action="formTag/form.do" method="post" methodParam="requestMethod" modelAttribute="user">
- <input type="hidden" name="requestMethod" value="head"/>
- <table>
- <tr>
- <td>Name:</td><td><form:input path="name"/></td>
- </tr>
- <tr>
- <td>Age:</td><td><form:input path="age"/></td>
- </tr>
- <tr>
- <td colspan="2"><input type="submit" value="提交"/></td>
- </tr>
- </table>
- </form:form>
<form:form action="formTag/form.do" method="post" methodParam="requestMethod" modelAttribute="user">
<input type="hidden" name="requestMethod" value="head"/>
<table>
<tr>
<td>Name:</td><td><form:input path="name"/></td>
</tr>
<tr>
<td>Age:</td><td><form:input path="age"/></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="提交"/></td>
</tr>
</table>
</form:form>
同時我們也要告訴HiddenHttpMethodFilter我們是使用哪個表單參數作爲methodParam,所以我們需要在配置HiddenHttpMethodFilter的時候指明methodParam對應的值。
- <filter>
- <filter-name>hiddenHttpMethodFilter</filter-name>
- <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
- <init-param>
- <param-name>methodParam</param-name>
- <param-value>requestMethod</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>hiddenHttpMethodFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
<init-param>
<param-name>methodParam</param-name>
<param-value>requestMethod</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
另外需要注意的是在有Multipart請求處理的時候HiddenHttpMethodFilter需要在Multipart處理之後執行,因爲在處理Multipart時需要從POST請求體中獲取參數。所以我們通常會在HiddenHttpMethodFilter之前設立一個MultipartFilter。MultipartFilter默認會去尋找一個名稱爲filterMultipartResolver的MultipartResolver bean對象來對當前的請求進行封裝。所以當你定義的MultipartResolver的名稱不爲filterMultipartResolver的時候就需要在定義MultipartFilter的時候通過參數multipartResolverBeanName來指定。
- <filter>
- <filter-name>multipartFilter</filter-name>
- <filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
- <init-param>
- <param-name>multipartResolverBeanName</param-name>
- <param-value>multipartResolver</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>multipartFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <filter>
- <filter-name>hiddenHttpMethodFilter</filter-name>
- <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
- <init-param>
- <param-name>methodParam</param-name>
- <param-value>requestMethod</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>hiddenHttpMethodFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
<filter>
<filter-name>multipartFilter</filter-name>
<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
<init-param>
<param-name>multipartResolverBeanName</param-name>
<param-value>multipartResolver</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>multipartFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
<init-param>
<param-name>methodParam</param-name>
<param-value>requestMethod</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>