转:使用Spring MVC表单标签

使用SpringMVC表单标签

概述

在低版本的Spring中,你必须通过JSTL或<spring:bind>将表单对象绑定到HTML表单页面中,对于习惯了Struts表单标签的开发者来说,SpringMVC的这一表现确实让人失望。不过这一情况已经一去不复返了,从Spring2.0开始,SpringMVC开始全面支持表单标签,通过SpringMVC表单标签,我们可以很容易地将控制器相关的表单对象绑定到HTML表单元素中。

在上一篇文章《SpringMVC的表单控制器》中(http://tech.it168.com/j/2007-07-26/200707261434046.shtml)我们已经使用到了部分的SpringMVC表单标签,在本文中我们将对SpringMVC表单标签进行全面的介绍,让我们首先从<form:form>标签开始吧。

form标签

和使用任何JSP扩展标签一样,在使用Spring表单标签之前,你必须在JSP页面中添加一行引用Spring表单标签的声明,如下所示:

<%@pagelanguage="java"contentType="text/html;charset=UTF-8"pageEncoding="UTF-8"%>

<%@taglibprefix="form"uri="http://www.springframework.org/tags/form"%>①引入标签的声明

<html>

…②声明后,在页面中就可以使用任意Spring表单标签了

</html>

一般情况下,我们使用“form”作为SpringMVC表单标签的前缀,当然只要愿意,你可以调整为其它的前缀名。在声明好标签引用后,就可以在该JSP文件中使用所有SpringMVC的表单标签了。下面是一个使用<form:form>表单标签的示例,它将最终生成一个HTML的form表单:

<form:form>

用户名:<form:inputpath="userName"/><br>

密码:<form:passwordpath="password"/><br>

Email:<form:inputpath="email"/><br>

<inputtype="submit"value="注册"name="testSubmit"/>

<inputtype="reset"value="重置"/>

</form:form>

回忆一下我们在《SpringMVC的表单控制器》(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代码自动包含表单提交地址:

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

2)<form:form>标签内部的组件标签(如<form:input>、<form:password>等)可以直接和表单控制器所对应的表单对象进行值绑定。

默认情况下,表单控制器将表单对象以“command”为名放到PageContext中,你可以通过表单控制器commandName属性的设置使用其它的名字(假设设置为“user”),这时你必须通过<form:formcommandname="user">显式指定绑定的表单对象名称。

除了commandName属性外,Spring表单标签拥有丰富的可设置属性,这些属性大都是HTML表单标签属性的镜像,如onclick、ondblclick、tabindex等等。需要注意的一点是这些属性都是小写的,而对应的HTML标签的属性则没有这个限制。但是有几个和HTML标签有区别的属性,我们通过表1进行说明:

表1表单元素标签特殊属性

目录说明

cssClass使用该属性指定表单元素CSS样式名,相当于HTML元素的class属性。示例:<form:inputpath="userName"cssclass="inputStyle"/>。

cssStyle直接通过该属性指定样式,相当于HTML元素的style属性。示例:

<form:inputpath="userName"cssstyle="width:100px"/>。

cssErrorClasscssClass表示表单元素未发生错误时对应的样式,而cssErrorClass表示表单元素发生错误时对应的样式,示例:

输入组件标签

表单中有一些用于接受输入值的组件,如单行文本框、多行文本框以及密码框,Spring为它们提供了对应的表单标签,请看下面的例子:

代码清单1使用输入组件标签的表单

<form:form>

用户名:<form:inputpath="userName"/><br>①单行文件框标签

密码:<form:passwordpath="password"/><br>②密码框标签

描述:<form:textareapath="desc"cols="20"rows="3"/><br>③多行文件框标签

<form:hiddenpath="times"/>④隐藏组件的值

<inputtype="submit"value="注册"name="testSubmit"/>

<inputtype="reset"value="重置"/>

</form:form>

正如你看到的,所有表单组件标签都通过path属性绑定表单对象的属性值,它支持级联属性,比如path="user.userName"将调用表单对象getUser.getUserName()绑定表单对象的属性值。这些表单组件标签拥有大多数HTML组件标签的镜像属性,如③处的<form:textarea>就使用了cols和rows属性设定列数和行数。

以上使用表单标签的页面的对应HTML页面如下所示:

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

用户名:<inputid="userName"name="userName"type="text"value=""/><br>

密码:<inputid="password"name="password"type="password"value=""/><br>

描述:<textareaid="desc"name="desc"rows="3"cols="20"></textarea><br>

<inputid="times"name="times"type="hidden"value="0"/>

<inputtype="submit"value="注册"name="testSubmit"/>

<inputtype="reset"value="重置"/>

</form>

单选框和复选框组件标签

单选框和复选框组件虽然在HTML中都对应<input>元素标签,但在SpringMVC表单标签中,它们分别对应两个更达意的标签:

<form:radiobutton>和<form:checkbox>。

radiobutton

单选框组件由两个同名的标签组件组成,当表单对象对应属性值和value值相等时,单选框选中。下面是一个代表性别的单选框:

<form:form>

性别:<form:radiobuttonpath="sex"value="0"/>男

<form:radiobuttonpath="sex"value="1"/>女

</form:form>

当表单对象的sex属性为0时(可以是String、int等可以自动转换为String的类型),所生成的HTML代码如下所示:

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

性别:<inputid="sex1"name="sex"type="radio"value="0"checked="checked"/>男

<inputid="sex2"name="sex"type="radio"value="1"/>女

</form>

checkbox

复选框组件标签相对来说复杂一些,复选框组件对应的表单属性不但可以boolean类型,还可以是String[]、Collection,Enum等类型。针对不同属性类型,复选框的选中状态的判断条件是不一样的:

boolean类型:当对应属性为true时,该复选框选中(一个属性仅对应一个复选框);

String[]、Collection或Enum类型:复选框对应值出现在对应属性列表中,该复选框选中;

其它类型:当复选框对应的值可以转换为对应属性值,该复选框选中。

假设用户注册的User表单对象包含了一个List类型的favorites属性:

importjava.util.List;

publicclassUser{

privateListfavorites;

publicListgetFavorites(){

returnfavorites;

}

publicvoidsetFavorites(Listfavorites){

this.favorites=favorites;

}

}

我们希望将其在页面中使用一个复选框组件绑定这个属性,则可以使用以下的代码:

代码清单2复选框标签的使用

<form:form>

兴趣爱好:

<form:checkboxpath="favorites"value="1"/>computer

<form:checkboxpath="favorites"value="2"/>sport

<form:checkboxpath="favorites"value="3"/>entertainment

<form:checkboxpath="favorites"value="4"/>literature

</form:form>

除了正常的path属性名外,还必须提供一个value属性,假设User表单对象的favorites属性包括了1和3的值,那么产生的HTML页面为:

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

兴趣爱好:<inputid="favorites1"name="favorites"type="checkbox"value="1"checked="checked"/>

<inputtype="hidden"value="1"name="_favorites"/>computer

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

<inputtype="hidden"value="1"name="_favorites"/>sport

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

<inputtype="hidden"value="1"name="_favorites"/>entertainment

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

<inputtype="hidden"value="1"name="_favorites"/>literature

</form>

大家可能已经注意到每个复选框组件的后台都跟着一个隐藏组件,这是因为当HTML页面中的复选框没有被选中时,这个复选框的值不会在表单提交时作为HTTP请求参数发送到服务器端,这给Spring的表单数据绑定造成了麻烦——因为无法触发setFavorites()方法的调用(如果原来已经有值,这个值不会被设置为空)。解决方法就是在每个复选框后面加一个隐藏组件,并且将对应的复选框名字前添加一个下划线("_")作为隐藏组件的名字。这样一来,你相当于告诉Spring“这个表单中存在这样一个复选框,我希望表单对象中对应的属性和这个checkbox的状态保持一致”。

假设复选框对应的选项在数据库或配置文件中定义,那么页面复选框标签就不能通过硬编码的方式指定,相反必须根据配置的选项数据动态产生。对于这样的需求,代码清单2的编写方式显然不能满足需求。回忆一下表单控制器的工作流程,我们知道可以通过复写referenceData()方法在表单显示前准备一些需要的数据,现在终于派上用场了,来看一下具体的实现:

代码清单3UserRegisterController:准备表单显示数据

packagecom.baobaotao.web.user;

importorg.springframework.ui.ModelMap;

publicclassUserRegisterControllerextendsSimpleFormController{

privateBbtForumbbtForum;

①创建初始表单对象

protectedObjectformBackingObject(HttpServletRequestrequest)

throwsException{

intuserId=ServletRequestUtils.getIntParameter(request,"userId",-1);

Useruser=bbtForum.getUser(userId);

user.setUserName("tom");

Listfavorites=newArrayList();①-1默认选中值为1和3的选项

favorites.add("1");

favorites.add("3");

user.setFavorites(favorites);

returnuser;

}

@Override②准备表单显示时需要的数据

protectedMapreferenceData(HttpServletRequestrequest)throwsException{

MapfavoriteMap=newLinkedHashMap();

favoriteMap.put("1","computer");

favoriteMap.put("2","sport");

favoriteMap.put("3","entertainment");

favoriteMap.put("4","literature");

②-1将表单页面需要的对象以ModelMap返回,最终将以属性名值对方式出现在请求属性中

returnnewModelMap().addObject("favoriteMap",favoriteMap);

}

@Override

protectedModelAndViewonSubmit(Objectcommand,BindExceptionerrors)

throwsException{

Useruser=(User)command;

bbtForum.registerUser(user);

returnnewModelAndView(getSuccessView(),"user",user);

}

}

相关推荐