概述 在低版本的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); } }