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); } }
在以上代码中我们覆盖了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表单标签,因此如实例那样混合使用二者可以如预期一样输出正确的结果。