7.2 文件下载

示例: Spring MVC的文件下载

可能很多读者会觉得, 文件下载太简单, 直接在页面给出一个超链接, 该链接的href属性等于要下载文件的文件名, 不就可以实现文件下载了吗? 这样做大部分时候的确可以实现文件下载, 但如果该文件的文件名为中文文件名, 在某些早期的浏览器上就会导致下载失败( 使用最新的FirefoxOperaChromeSafari都可以正常下载文件名为中文的文件)。
Spring MVC提供了一个ResponseEntity类型, 使用它可以很方便地定义返回的BodyBuilderHttpHeadersHttpStatus

download方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@GetMapping(value = "/download")
public ResponseEntity<byte[]> download(HttpServletRequest request,
@RequestParam("filename") String filename,
@RequestHeader("User-Agent") String userAgent) throws Exception
{
// 下载文件路径
String path = request.getServletContext().getRealPath("/images");
// 构建File
File file = new File(path + File.separator + filename);
// ok表示Http协议中的状态 200
BodyBuilder builder = ResponseEntity.ok();
// 内容长度
builder.contentLength(file.length());
// application/octet-stream : 二进制流数据(最常见的文件下载)。
builder.contentType(MediaType.APPLICATION_OCTET_STREAM);
// 使用URLDecoder.decode对文件名进行解码
filename = URLEncoder.encode(filename, "UTF-8");
// 设置实际的响应文件名,告诉浏览器文件要用于【下载】、【保存】attachment 以附件形式
// 不同的浏览器,处理方式不同,要根据浏览器版本进行区别判断
if (userAgent.indexOf("MSIE") > 0)
{
// 如果是IE,只需要用UTF-8字符集进行URL编码即可
builder.header("Content-Disposition",
"attachment; filename=" + filename);
} else
{
// 而FireFox、Chrome等浏览器,则需要说明编码的字符集
// 注意filename后面有个*号,在UTF-8后面有两个单引号!
builder.header("Content-Disposition",
"attachment; filename*=UTF-8''" + filename);
}
return builder.body(FileUtils.readFileToByteArray(file));
}

代码分析

download处理方法接收到页面传递的文件名filename后, 使用Apache Commons FileUpload组件的FileUtils读取项目的images文件夹下的该文件, 并将其构建成ResponseEntity对象返回客户端下载。
使用ResponseEntity对象, 可以很方便地定义返回的BodyBuilderHttpHeadersHttpStatusBodyBuilder对象用来构建返回的BodyHttpHeaders类型代表的是Http协议中的头信息;
HttpStatus类型代表的是Http协议中的状态。 上面代码中的MediaType, 代表的是Internet Media Type, 即互联网媒体类型, 也叫作MIME类型。
Http协议消息头中, 使用Content- Type来表示具体请求中的媒体类型信息。 有关BodyBuilderMediaTypeHttpStatus类的详细信息参考Spring MVCAPI文档。

测试

单击下载页面的超链接, 显示文件正在下载。 结果如图 7.3 所示。
单击“ 浏览” 按钮, 选择下载文件保存的路径, 然后单击“ 确定” 按钮, 文件即会被顺利下载并保存。

6.0 第6章概述

本章要点

  • Spring MVC的数据绑定流程
  • 使用ConversionService转换数据
  • 使用@ IntitBinder转换数据
  • 使用WebBindingInitializer转换数据
  • 使用FormatterFormatterRegistrar格式化数据
  • 使用AnnotationFormatterFactory格式化数据
  • SpringValidation校验框架
  • JSR 303 校验

Spring MVC会根据请求方法签名不同, 将请求消息中的信息以一定的方式转换并绑定到请求方法的参数。 在请求消息到达真正调用处理方法的这一段时间内,Spring MVC还会完成很多其他的工作, 包括请求信息转换、 数据转换、 数据格式化以及数据校验等。

4.1.13 errors标签

Spring MVCerrors标签是对应于Spring MVCErrors对象的,它的作用就是显示Errors对象中包含的错误信息。如果Errors不为null,则会渲染一个HTMLspan元素,用来显示错误信息。

属性 描述
cssclass 定义要应用到被渲染的errors元素CSS
cssStyle 定义要应用到被渲染的errors元素CSS样式
htmlEscape boolean值,表示被渲染的值是否应该进行HTML转义
delimiter 定义两个input元素之间的分隔符,默认没有分隔符
path 要绑定的属性路径

利用errors标签来显示Errors时,是通过errors标签的**path属性**绑定一个错误信息实现的。可以通过path属性来显示两种类型的错误信息:

  • 所有的错误信息,这个时候path的值应该设置为”*“。
  • 当前对象的某一个属性的错误信息,这个时候path的值应为所需显示的属性的名称。

实例

域对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 域对象,实现序列化接口
public class User
implements Serializable
{
private static final long serialVersionUID = 1L;
private String username;
private String sex;
private Integer age;
public User()
{
super();
}
// 此处省略getter和setter方法,请自己补上
}

测试链接

1
<a href="registerForm">registerForm</a>

返回表单的请求处理方法

1
2
3
4
5
6
7
8
@GetMapping(value = "/registerForm")
public String registerForm(Model model)
{
User user = new User();
// model中添加属性user,值是user对象
model.addAttribute("user", user);
return "registerForm";
}

表单标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<!-- 表单绑定user对象 -->
<form:form modelAttribute="user" method="post" action="register">
<table>
<tr>
<td>姓名:</td>
<td>
<!-- 绑定user对象的username成员变量 -->
<form:input path="username" />
</td>
<td>
<font color="red">
<!-- 绑定user对象的username成员变量 出错时显示-->
<form:errors path="username" />
</font>
</td>
</tr>
<tr>
<td>性别:</td>
<td>
<!-- 绑定user对象的sex成员变量 -->
<form:input path="sex" />
</td>
<td>
<font color="red">
<!-- 绑定user对象的sex成员变量 出错时显示 -->
<form:errors path="sex" />
</font>
</td>
</tr>
<tr>
<td>年龄:</td>
<!-- 绑定user对象的sex成员变量 -->
<td>
<form:input path="age" />
</td>
<td>
<font color="red">
<!-- 绑定user对象的sex成员变量 出错时显示 -->
<form:errors path="age" />
</font>
</td>
</tr>
<tr>
<td>
<input type="submit" value="注册" />
</td>
</tr>
</table>
</form:form>

渲染效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<!-- 表单绑定user对象 -->
<form id="user" action="register" method="post">
<table>
<tr>
<td>姓名:</td>
<td>
<!-- 绑定user对象的username成员变量 -->
<input id="username" name="username" type="text" value="" />
</td>
<td>
<font color="red">
<!-- 绑定user对象的username成员变量 出错时显示-->
</font>
</td>
</tr>
<tr>
<td>性别:</td>
<td>
<!-- 绑定user对象的sex成员变量 -->
<input id="sex" name="sex" type="text" value="" />
</td>
<td>
<font color="red">
<!-- 绑定user对象的sex成员变量 出错时显示 -->
</font>
</td>
</tr>
<tr>
<td>年龄:</td>
<!-- 绑定user对象的sex成员变量 -->
<td>
<input id="age" name="age" type="text" value="" />
</td>
<td>
<font color="red">
<!-- 绑定user对象的sex成员变量 出错时显示 -->
</font>
</td>
</tr>
<tr>
<td>
<input type="submit" value="注册" />
</td>
</tr>
</table>
</form>

现在表单还没填写,不存在错误输入,所以错误提示标签不会渲染出来,我们只能看到错误提示标签上面的注释.

填写表单

故意少填写:
这里有一张图片
然后提交,这将会提交给register这个请求处理方法。

表单验证请求处理方法

由于register中使用@Validated注解了绑定表单的参数user,表单的参数会默认复制给user的同名属性,然后只用验证器UserValidator验证user对象中的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@InitBinder
public void initBinder(DataBinder binder)
{
// 设置验证的类为UserValidator
binder.setValidator(new UserValidator());
}
@PostMapping(value = "/register")
//@Validated表示校验该域对象
public String register(@Validated User user, Errors errors)
{
// 如果Errors对象有Field错误的时候,重新跳回注册页面,否则正常提交
if (errors.hasFieldErrors())
return "registerForm";
return "submit";
}

验证器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import org.fkit.domain.User;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
public class UserValidator
implements Validator
{
@Override
public boolean supports(Class<?> clazz)
{
return User.class.equals(clazz);
}
@Override
public void validate(Object object, Errors errors)
{
// 验证username、sex和age是否为null
ValidationUtils.rejectIfEmpty(errors, "username", null, "用户名不能为空");
ValidationUtils.rejectIfEmpty(errors, "sex", null, "性别不能为空");
ValidationUtils.rejectIfEmpty(errors, "age", null, "年龄不能为空");
}
}

渲染效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!-- 表单绑定user对象 -->
<form id="user" action="register" method="post">
<table>
<tr>
<td>姓名:</td>
<td>
<!-- 绑定user对象的username成员变量 -->
<input id="username" name="username" type="text" value="x" />
</td>
<td>
<font color="red">
<!-- 绑定user对象的username成员变量 出错时显示-->
</font>
</td>
</tr>
<tr>
<td>性别:</td>
<td>
<!-- 绑定user对象的sex成员变量 -->
<input id="sex" name="sex" type="text" value="x" />
</td>
<td>
<font color="red">
<!-- 绑定user对象的sex成员变量 出错时显示 -->
</font>
</td>
</tr>
<tr>
<td>年龄:</td>
<!-- 绑定user对象的sex成员变量 -->
<td>
<input id="age" name="age" type="text" value="" />
</td>
<td>
<font color="red">
<!-- 绑定user对象的sex成员变量 出错时显示 -->
<span id="age.errors">年龄不能为空</span>
</font>
</td>
</tr>
<tr>
<td>
<input type="submit" value="注册" />
</td>
</tr>
</table>
</form>

最后一个文本框我没有填写,验证器把errors渲染成spen标签,然后重新刷新页面显示出来.

显示效果

这里有一张图片

4.1.10 select标签

Spring MVCselect标签会渲染一个HTMLselect元素。
被渲染元素的选项可能来自其items属性的一个CollectinMapArray, 或者来自一个嵌套的option或者options标签。

属性

select标签可使用如表4.11所示的属性。
表4.11中列出的只是Spring MVCselect标签的常用属性, 并没有包含HTML的相关属性。

属性 描述
cssclass 定义要应用到被渲染的select元素的CS
cssStyle 定义要应用到被渲染的select元素的CSS样式
cssErrorClass 定义要应用到被渲染的select元素的CSS类,如果bound属性中包含错误,则覆盖cssclass属性值
htmlEscape boolean值,表示被渲染的值是否应该进行HTML转义
path 要绑定的属性路径
items 用于生成select元素的对象的Collection,Map或者Array
itemLabel item属性中定义的CollectionMap或者Array中的对象属性,为每个select元素提供label
itemValue item属性中定义的CollectionMap或者Array中的对象属性,为每个select元素提供值

items属性

其中,items属性特别有用, 因为它可以绑定到对象的CollectionMapArray上, 为select元素生成选项。

领域对象

User.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 域对象,实现序列化接口
public class User
implements Serializable
{
private static final long serialVersionUID = 1L;
// 部门编号
private Integer deptId;
public User()
{
super();
// TODO Auto-generated constructor stub
}
// 此处省略getter和setter方法,请自己补上
}

Dept

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Dept
implements Serializable
{
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
public Dept()
{
super();
// TODO Auto-generated constructor stub
}
public Dept(Integer id, String name)
{
super();
this.id = id;
this.name = name;
}
// 此处省略getter和setter方法,请自己补上
}

option标签

Spring MVCoption标签会渲染select元素中使用的一个HTMLoption元素。
option标签可使用如表 4.12 所示的属性。
表 4.12 中列出的只是Spring MVCoption标签的常用属性, 并没有包含HTML的相关属性。

属性

属性 描述
cssClass 定义要应用到被渲染的option元素的CSS
cssStyle 定义要应用到被渲染的option元素的CSS样式
cssErrorClass 定义要应用到被渲染的option元素的CSS类,如果bound属性中包含错误,则覆盖cssClass属性值
htmlEscape boolean值,表示被渲染的值是否应该进行HTML转义

测试链接

1
<a href="selectForm">selectForm</a><br>

请求处理方法

1
2
3
4
5
6
7
8
9
@GetMapping(value = "/selectForm")
public String selectForm(Model model)
{
User user = new User();
// 设置deptId的值,页面的select下拉框对应的option项会被选中
user.setDeptId(2);
model.addAttribute("user", user);
return "selectForm";
}

表单标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!--绑定模型中的user属性 -->
<form:form modelAttribute="user" method="post" action="selectForm">
<table>
<tr>
<td>部门:</td>
<!-- 绑定user属性表示的对象中的depathID成员变量 -->
<!-- 如果该成员变量与下面的option标签的value属性的属性值相等的话 -->
<!-- 就默认选中该选项 -->
<td><form:select path="deptId">
<form:option value="1">财务部</form:option>
<form:option value="2">开发部</form:option>
<form:option value="3">销售部</form:option>
</form:select></td>
</tr>
</table>
</form:form>

渲染效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--绑定模型中的user属性 -->
<form id="user" action="selectForm" method="post">
<table>
<tr>
<td>部门:</td>
<!-- 绑定user属性表示的对象中的depathID成员变量 -->
<!-- 如果该成员变量与下面的option标签的value属性的属性值相等的话 -->
<!-- 就默认选中该选项 -->
<td>
<select id="deptId" name="deptId">
<option value="1">财务部</option>
<option value="2" selected="selected">开发部</option>
<option value="3">销售部</option>
</select>
</td>
</tr>
</table>
</form>

可以看到第二个选项设置了selected="selected"属性,该选型会默认选中.具体选中哪个选项通过设置绑定的对象的对应属性的值来设定,对象的值和选项的value属性相等的会被默认选中.

显示效果

这里有一张图片

select标签 map作为数据源

测试链接

1
<a href="selectForm2">selectForm2</a><br>

请求处理方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@GetMapping(value = "/selectForm2")
public String selectForm2(Model model)
{
User user = new User();
// key为2的将会被选中
user.setDeptId(2);
// 页面展现的可供选择的select下拉框内容deptMap
Map<Integer, String> deptMap = new HashMap<Integer, String>();
deptMap.put(1, "财务部");
deptMap.put(2, "开发部");
deptMap.put(3, "销售部");
model.addAttribute("user", user);
model.addAttribute("deptMap", deptMap);
return "selectForm2";
}

表单标签库

1
2
3
4
5
6
7
8
9
<form:form modelAttribute="user" method="post" action="selectForm2">
<table>
<tr>
<td>部门:</td>
<td><form:select path="deptId" items="${deptMap}" />
</td>
</tr>
</table>
</form:form>

form标签的modelAttribute="user"表示绑定model中的user属性也就是user对象.
Spring MVCselect标签的path="deptId"属性表示该select标签绑定user对象的deptId成员变量,

渲染结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<form id="user" action="selectForm2" method="post">
<table>
<tr>
<td>部门:</td>
<td>
<select id="deptId" name="deptId">
<option value="1">财务部</option>
<option value="2" selected="selected">开发部</option>
<option value="3">销售部</option>
</select>
</td>
</tr>
</table>
</form>

显示效果

这里有一张图片
使用这种方式将使用map中的值作为显示文本,使用key作为option标签的value属性

options标签

Spring MVCoptions标签会渲染select元素中使用的一个HTMLoption元素列表。options标签可使用如表 4.13 所示的属性。 表 4.13 中列出的只是Spring MVCoptions标签的常用属性, 并没有包含HTML的相关属性。

属性 描述
cssClass 定义要应用到被渲染的option元素的CSS
cssStyle 定义要应用到被渲染的option元素的CSS样式
cssErrorclass 定义要应用到被渲染的option元素的CSS类,如果bound属性中包含错误,则覆盖cssClass属性值
htmlEscape boolean值,表示被渲染的值是否应该进行HIML转义
items 用于生成option列表元素的对象的CollectionMap或者Array
itemLabel items属性中定义的Collection,Map或者Array中的对象属性,为每个option元素提供label
itemValue items属性中定义的Collection,Map或者Array中的对象属性,为每个option元素提供值

select option标签 map数据源

测试链接

1
<a href="selectForm3">selectForm3</a><br>

请求处理方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@GetMapping(value = "/selectForm3")
public String selectForm3(Model model)
{
User user = new User();
user.setDeptId(2);
// 页面展现的可供选择的select下拉框内容deptMap
Map<Integer, String> deptMap = new HashMap<Integer, String>();
deptMap.put(1, "财务部");
deptMap.put(2, "开发部");
deptMap.put(3, "销售部");
model.addAttribute("user", user);
model.addAttribute("deptMap", deptMap);
return "selectForm3";
}

表单标签数据绑定

1
2
3
4
5
6
7
8
9
10
<form:form modelAttribute="user" method="post" action="selectForm">
<table>
<tr>
<td>部门:</td>
<td><form:select path="deptId">
<form:options items="${deptMap}" />
</form:select></td>
</tr>
</table>
</form:form>

使用map作为数据源的options标签时,使用mapkey作为option标签的value属性的值,使用mapvalue作为显示文本。

渲染效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<form id="user" action="selectForm" method="post">
<table>
<tr>
<td>部门:</td>
<td>
<select id="deptId" name="deptId">
<option value="1">财务部</option>
<option value="2" selected="selected">开发部</option>
<option value="3">销售部</option>
</select>
</td>
</tr>
</table>
</form>

显示效果

这里有一张图片

select options绑定Object列表

Spring MVCoptions标签会渲染select元素中使用的一个HTMLoption元素列表。options标签可使用如表 4.13 所示的属性。 表 4.13 中列出的只是Spring MVCoptions标签的常用属性, 并没有包含HTML的相关属性。

4.1.12 options标签

在实际开发中,经常会出现一种情况,即**select下拉框中的数据来自于数据库的表数据,并且获取的数据被封装到JavaBean。此时,就可以使用select标签或者**options标签的itemsitemLabelitemValue属性来加载数据。

测试链接

1
<a href="selectForm4">selectForm4</a><br>

请求处理方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@GetMapping(value = "/selectForm4")
public String selectForm4(Model model)
{
User user = new User();
user.setDeptId(2);
// 页面展现的可供选择的select下拉框内容deptList,其中的元素的Dept对象
// 模拟从数据库获取到部门信息封装到对象当中
List<Dept> deptList = new ArrayList<Dept>();
deptList.add(new Dept(1, "财务部"));
deptList.add(new Dept(2, "开发部"));
deptList.add(new Dept(3, "销售部"));
model.addAttribute("user", user);
model.addAttribute("deptList", deptList);
return "selectForm4";
}

selectForm4方法中模拟从数据库中获取部门信息,并将其封装到Dept对象中,且将多个部门信息装载到List集合中,最后添加到Model当中。

表单标签

1
2
3
4
5
6
7
8
9
10
11
12
13
<form:form modelAttribute="user" method="post" action="selectForm">
<table>
<tr>
<td>部门:</td>
<td><form:select path="deptId">
<!--itemLabel表示该对象的要显示的提示文本 -->
<!--itemValue表示使用显示该对象的id成员变量的值作为option标签的value属性 -->
<form:options items="${deptList}"
itemLabel="name" itemValue="id" />
</form:select></td>
</tr>
</table>
</form:form>

selectForm4.jsp页面的options标签的items标签加载Model中的deptList,并将集合中的Dept对象的id属性设置为optionvalue,name属性设置为optionlabel

渲染效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<form id="user" action="selectForm" method="post">
<table>
<tr>
<td>部门:</td>
<td>
<select id="deptId" name="deptId">
<option value="1">财务部</option>
<option value="2" selected="selected">开发部</option>
<option value="3">销售部</option>
</select>
</td>
</tr>
</table>
</form>

显示效果

这里有一张图片

4.1.8 radiobutton标签

用途 渲染成单元按钮

Spring MVCradiobutton标签会被渲染为一个类型为radio的普通HTML input标签。

属性

radiobutton标签可使用如表4.9所示的属性。 表4.9中列出的只是Spring MVCradiobutton标签的常用属性, 并没有包含HTML的相关属性。

属性 描述
cssClass 定义要应用到被渲染的radiobutton元素的CSS
cssStyle 定义要应用到被渲染的radiobutton元素的CSS样式
cssErrorClass 定义要应用到被渲染的radiobutton元素的CSS类,如果bound属性中包含错误,则覆盖cssClass属性值
htmlEscape boolean值,表示被渲染的值是否应该进行HTML转义
path 要绑定的属性路径
label 要作为label被渲染复选框的值

示例:radiobutton标签的使用

项目结构

展开/折叠
G:\Desktop\随书源码\Spring+Mybatis企业应用实战(第2版)\codes\04\RadiobuttonTest
├─src\
│ └─org\
│   └─fkit\
│     ├─controller\
│     │ └─UserController.java
│     └─domain\
│       └─User.java
└─WebContent\
  ├─index.jsp
  ├─META-INF\
  │ └─MANIFEST.MF
  └─WEB-INF\
    ├─content\
    │ ├─radiobuttonForm.jsp
    │ ├─radiobuttonsForm.jsp
    │ └─radiobuttonsForm2.jsp
    ├─lib\
    │ ├─commons-logging-1.2.jar
    │ ├─spring-aop-5.0.1.RELEASE.jar
    │ ├─spring-aspects-5.0.1.RELEASE.jar
    │ ├─spring-beans-5.0.1.RELEASE.jar
    │ ├─spring-context-5.0.1.RELEASE.jar
    │ ├─spring-context-indexer-5.0.1.RELEASE.jar
    │ ├─spring-context-support-5.0.1.RELEASE.jar
    │ ├─spring-core-5.0.1.RELEASE.jar
    │ ├─spring-expression-5.0.1.RELEASE.jar
    │ ├─spring-instrument-5.0.1.RELEASE.jar
    │ ├─spring-jcl-5.0.1.RELEASE.jar
    │ ├─spring-jdbc-5.0.1.RELEASE.jar
    │ ├─spring-jms-5.0.1.RELEASE.jar
    │ ├─spring-messaging-5.0.1.RELEASE.jar
    │ ├─spring-orm-5.0.1.RELEASE.jar
    │ ├─spring-oxm-5.0.1.RELEASE.jar
    │ ├─spring-test-5.0.1.RELEASE.jar
    │ ├─spring-tx-5.0.1.RELEASE.jar
    │ ├─spring-web-5.0.1.RELEASE.jar
    │ ├─spring-webflux-5.0.1.RELEASE.jar
    │ ├─spring-webmvc-5.0.1.RELEASE.jar
    │ └─spring-websocket-5.0.1.RELEASE.jar
    ├─springmvc-config.xml
    └─web.xml

User.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 域对象,实现序列化接口
public class User
implements Serializable
{
private static final long serialVersionUID = 1L;
// 定义一个属性,用来绑定表单中的数据
private String sex;
// getter,setter方法
public String getSex()
{
return sex;
}
public void setSex(String sex)
{
this.sex = sex;
}
}

User类中定义了一个属性sex, 用来绑定页面的radiobutton标签数据。

UserController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package org.fkit.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.fkit.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class UserController
{

@GetMapping(
value = "/radiobuttonForm")
public String registerForm(Model model)
{
// 创建领域对象
User user = new User();
// value值相等的单选按钮将会被选中
user.setSex("女");
// 添加领域对象到模型(也就去请求域中)
model.addAttribute("user", user);
// 返回视图
return "radiobuttonForm";
}

@GetMapping(
value = "/radiobuttonsForm")
public String registerForm2(Model model)
{
User user = new User();
// value值相等的会被选中中
user.setSex("男");
// 页面展现的可供选择的单选框内容sexList
List<String> sexList = new ArrayList<String>();
// 数据源中的值将会填写到单选按钮的value属性值
sexList.add("男");
sexList.add("女");
sexList.add("不男不女");
sexList.add("半男半女");
model.addAttribute("user", user);
model.addAttribute("sexList", sexList);
return "radiobuttonsForm";
}
@GetMapping(
value = "/radiobuttonsForm2")
public String registerForm3(Model model)
{
User user = new User();
// 设置sex变量的值为"1",页面的radio单选框的value=男会被选中
user.setSex("1");
// 页面展现的可供选择的单选框内容sexMap
Map<String, String> sexMap = new HashMap<String, String>();
sexMap.put("1", "男");
sexMap.put("2", "女");
sexMap.put("3", "不男不女");
sexMap.put("4", "半男半女");
model.addAttribute("user", user);
model.addAttribute("sexMap", sexMap);
return "radiobuttonsForm2";
}

}

radiobuttonForm.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>测试radiobutton标签</title>
</head>
<body>
<h3>form:radiobutton测试</h3>
<%-- modelAttribute="user"表示绑定到域中的user属性 --%>
<form:form modelAttribute="user" method="post"
action="radiobuttonForm">
<table>
<tr>
<td>性别:</td>
<%-- path指定user属性中的成员变量名称 --%>
<%-- value属性的值 等于 user对象的sex属性的值 的时候选中 --%>
<td><form:radiobutton path="sex" value="男" />男&nbsp;
<form:radiobutton path="sex" value="女" />女&nbsp;
<form:radiobutton path="sex" value="不男不女" />不男不女(自己写的文本)&nbsp;
<form:radiobutton path="sex" value="半男半女" />不男不女(自己写的文本)&nbsp;</td>
</tr>
</table>
</form:form>
</body>
</html>

web.xml文件和springmvc-config.xml文件与之前讲述的一致, 此处不再赘述。

测试

部署RadiobuttonTest这个Web应用, 在浏览器中输入如下URL来测试应用:

渲染效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- modelAttribute="user"表示绑定到域中的user属性 -->
<form id="user" action="radiobuttonForm" method="post">
<table>
<tr>
<td>性别:</td>
<!--path指定user属性中的成员变量名称 -->
<!--value属性的值于user对象的sex属性的值相等的时候选中 -->
<td>
<input id="sex1" name="sex" type="radio" value="男" />&nbsp;
<input id="sex2" name="sex" type="radio" value="女" checked="checked" />&nbsp;
<input id="sex3" name="sex" type="radio" value="不男不女" />不男不女(自己写的文本)&nbsp;
<input id="sex4" name="sex" type="radio" value="半男半女" />不男不女(自己写的文本)&nbsp;</td>
</tr>
</table>
</form>

显示效果

这里有一张图片
使用这种方式按钮的提示文本要自己

4.1.9radiobuttons标签

Spring MVCradiobuttons标签会渲染多个类型为radio的普通HTML input标签。

属性

radiobuttons标签可使用如表 4.10 所示的属性。 表 4.10 中列出的只是Spring MVCradiobuttons标签的常用属性, 并没有包含HTML的相关属性。

属性 描述
cssClass 定义要应用到被渲染的radio元素的CSS
cssTyle 定义要应用到被渲染的radio元素的CSS样式
cssErrorClass 定义要应用到被渲染的radio元素的CSS类,如果bound属性中包含错误,则覆盖cssClass属性值
htmlEscape boolean值,表示被渲染的值是否应该进行HTML转义
path 要绑定的属性路径
items 用于生成radio元素的对象的CollectionMap或者Amay
itemLabel item属性中定义的CollectionMap或者Aay中的对象属性,为每个radio元素提供label
itemValue item属性中定义的CollectionMap或者Amay中的对象属性,为每个radio元素提供值
delimiter 定义两个Input元素之间的分隔符,默认没有分隔符

相对于一个radiobutton标签只能生成一个对应的单选框, 一个radiobuttons标签将根据其绑定的数据生成多个单选框。
radiobuttons绑定的数据可以是数组集合Map

items指定选项列表 path指定选中哪个选项

在使用radiobuttons时有两个属性是必须指定的, 一个是path, 另一个是items

  • items表示当前要用来显示的项有哪些,
  • path所绑定的表单对象的属性表示当前表单对象拥有的项, 即在items所显示的所有项中表单对象拥有的项会被设定为选中状态。

    示例:radiobuttons标签的使用

使用数组或集合作为数据源

请求处理方法 registerForm2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@GetMapping(value = "/radiobuttonsForm")
public String registerForm2(Model model)
{
User user = new User();
// value值相等的会被选中中
user.setSex("男");
// 页面展现的可供选择的单选框内容sexList
List<String> sexList = new ArrayList<String>();
//数据源中的值将会填写到单选按钮的value属性值
sexList.add("男");
sexList.add("女");
sexList.add("不男不女");
sexList.add("半男半女");
model.addAttribute("user", user);
model.addAttribute("sexList", sexList);
return "radiobuttonsForm";
}

radiobuttonsForm.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<!DOCTYPE>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>测试radiobuttons标签</title>
</head>
<body>
<h3>form:radiobuttons测试</h3>
<!-- 绑定模型中的user属性对应的对象 -->
<form:form modelAttribute="user" method="post"
action="radiobuttonsForm">
<table>
<tr>
<td>性别:</td>
<!-- items绑定数据源,数据源可以是数组,集合,Map, -->
<!-- 数据源中的数据将会被渲染成一个个选项 -->
<!-- path绑定模型中user属性对应的对象的sex成员变量, -->
<!-- 该成员变量的值如果在数据源中找到,将会勾选值相等的选项 -->
<td><form:radiobuttons path="sex" items="${sexList }" /></td>
</tr>
</table>
</form:form>
</body>
</html>

测试

在浏览器中输入如下URL来测试应用:

http://localhost:8080/RadiobuttonTest/radiobuttonsForm

渲染效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<form id="user" action="radiobuttonsForm" method="post">
<table>
<tr>
<td>性别:</td>
<td>
<span>
<input id="sex1" name="sex" type="radio" value="男" checked="checked" />
<label for="sex1"></label>
</span>
<span>
<input id="sex2" name="sex" type="radio" value="女" />
<label for="sex2"></label>
</span>
<span>
<input id="sex3" name="sex" type="radio" value="不男不女" />
<label for="sex3">不男不女</label>
</span>
<span>
<input id="sex4" name="sex" type="radio" value="半男半女" />
<label for="sex4">半男半女</label>
</span>
</td>
</tr>
</table>
</form>

显示效果

这里有一张图片
、这里与radiobutton的区别在于, 之前的页面有两个radiobutton标签, 而现在页面只有一个radiobuttons标签, 单选框的valuelabel来自于后台的List集合。
我们介绍的这种情况是使用List集合作为显示单选框项的数据源, 可以看到, 它所呈现出来的标签label和它的是一样的。 使用ArraySet作为数据源也是这样。

<span>
    <input id="sex1" name="sex" type="radio" value="" checked="checked" />
    <label for="sex1"></label>
</span>

使用Map作为数据源

那么要让radiobuttons呈现出来的labelvalue不同应该怎么做呢? 这时我们可以使用Map作为数据源。 当使用Map作为radiobuttonsitems属性的数据源时,

  • Map集合的key将作为真正的单选框的value
  • Map集合的value将作为label进行显示。

当使用Map作为radiobuttonsitems属性的数据源时我们绑定的表单对象属性的类型可以是Array、 集合和Map, 这种情况就是判断items属性指定的Map中是否含有对应的key来决定当前的单选框是否处于选中状态。

请求处理方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@GetMapping(value = "/radiobuttonsForm2")
public String registerForm3(Model model)
{
User user = new User();
// 设置sex变量的值为"1",页面的radio单选框的value=男会被选中
user.setSex("1");
// 页面展现的可供选择的单选框内容sexMap
Map<String, String> sexMap = new HashMap<String, String>();
sexMap.put("1", "男");
sexMap.put("2", "女");
sexMap.put("3", "不男不女");
sexMap.put("4", "半男半女");
model.addAttribute("user", user);
model.addAttribute("sexMap", sexMap);
return "radiobuttonsForm2";
}

registerForm3方法中, 提供给页面显示的可被选择的单选框内容sexMap是一个Map, 而user对象的sex变量中保存的正是sexMap中的key, 其用来决定页面的单选框是否处于选中状态。

radiobuttonsForm2.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>测试radiobuttons标签</title>
</head>
<body>
<h3>form:radiobuttons测试</h3>
<form:form modelAttribute="user" method="post"
action="radiobuttonForm2">
<table>
<tr>
<td>性别:</td>
<td><form:radiobuttons path="sex" items="${sexMap }" /></td>
</tr>
</table>
</form:form>
</body>
</html>

测试

在浏览器中输入如下URL来测试应用:

http://localhost:8080/RadiobuttonTest/radiobuttonsForm2

请求的结果和图 4.5 所示的一致, 查看源代码, 发现radiobuttonsvaluelabel不同了,value的值正是Mapkey, 而label的值正是Mapvalue

渲染结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<form id="user" action="radiobuttonForm2" method="post">
<table>
<tr>
<td>性别:</td>
<td>
<span>
<input id="sex1" name="sex" type="radio" value="1" checked="checked" />
<label for="sex1"></label>
</span>
<span>
<input id="sex2" name="sex" type="radio" value="2" />
<label for="sex2"></label>
</span>
<span>
<input id="sex3" name="sex" type="radio" value="3" />
<label for="sex3">不男不女</label>
</span>
<span>
<input id="sex4" name="sex" type="radio" value="4" />
<label for="sex4">半男半女</label>
</span>
</td>
</tr>
</table>
</form>

使用这种方式同样不需要再jsp中自己写上单选按钮的提示文本,Spring MVC会生成label标签作为提示文本,lable标签中的内容对应数据源map中的值,map中的key作为单选按钮value属性的值:

<span>
    <input id="sex1" name="sex" type="radio" value="1" checked="checked" />
    <label for="sex1"></label>
</span>

显示效果

这里有一张图片

itemLabel和itemValue属性

当使用Array或者集合作为数据源, 且里面的元素都是一个domain对象时, 我们还可以使用radiobuttons标签的itemLabelitemValue属性来表示, 使用数组或者集合中元素对象的哪一个属性作为需要呈现的单选框的labelvalue。 用法和之前checkboxes类似, 此处不再赘述。

4.1.7 checkboxes标签

渲染成多个多框

Spring MVCcheckboxes标签会渲染多个类型为checkbox的普通HTML input标签。

属性

checkboxes标签可使用如表4.8所示的属性。表4.8中列出的只是SpringMVCcheckboxes标签的常用属性,并没有包含HTML的相关属性。

属性 描述
cssClass 定义要应用到被渲染的checkbox元素的CSS
cssStyle 定义要应用到被渲染的checkbox元素的CSS样式
cssErrorClass 定义要应用到被渲染的checkbox元素的CSS类,如果bound属性中宝行错误,则覆盖cssClass属性值
htmlEscape boolean值,表示被渲染的值是否应该进行HTML转义
path 要绑定的属性的路径
items 用于生成checkbox元素的对象的Collection,Map或者Array
itemLabel item属性中定义的Collection,Map或者Array中对象的属性,为每个checkbox元素提供label
itemValue item属性中定义的Collection,Map或者Array中的对象属性,为每个checkbox元素提供值
delimiter 定义两个input元素之间的分割符,默认没有分割符

优点:可生成多个复选框

相对于一个checkbox标签只能生成一个对应的复选框而言,一个checkboxes标签将根据其绑定的数据生成多个复选框。

可绑定的数据类型

checkboxes绑定的数据可以是数组集合Map

必须属性 path items

在使用checkboxes标签时有两个属性是必须指定的,一个是path,另一个是items

  • items表示当前要用来显示的项有哪些,
  • path所绑定的表单对象的属性表示当前表单对象拥有的项,即在items所显示的所有项中表单对象拥有的项会被设定为选中状态。

示例:checkboxes标签的使用

项目结构

展开/折叠
G:\Desktop\随书源码\Spring+Mybatis企业应用实战(第2版)\codes\04\CheckboxesTest
├─src\
│ └─org\
│   └─fkit\
│     ├─controller\
│     │ └─UserController.java
│     └─domain\
│       ├─Dept.java
│       ├─Employee.java
│       └─User.java
└─WebContent\
  ├─index.jsp
  ├─META-INF\
  │ └─MANIFEST.MF
  └─WEB-INF\
    ├─content\
    │ ├─checkboxesForm.jsp
    │ ├─checkboxesForm2.jsp
    │ └─checkboxesForm3.jsp
    ├─lib\
    │ ├─commons-logging-1.2.jar
    │ ├─spring-aop-5.0.1.RELEASE.jar
    │ ├─spring-aspects-5.0.1.RELEASE.jar
    │ ├─spring-beans-5.0.1.RELEASE.jar
    │ ├─spring-context-5.0.1.RELEASE.jar
    │ ├─spring-context-indexer-5.0.1.RELEASE.jar
    │ ├─spring-context-support-5.0.1.RELEASE.jar
    │ ├─spring-core-5.0.1.RELEASE.jar
    │ ├─spring-expression-5.0.1.RELEASE.jar
    │ ├─spring-instrument-5.0.1.RELEASE.jar
    │ ├─spring-jcl-5.0.1.RELEASE.jar
    │ ├─spring-jdbc-5.0.1.RELEASE.jar
    │ ├─spring-jms-5.0.1.RELEASE.jar
    │ ├─spring-messaging-5.0.1.RELEASE.jar
    │ ├─spring-orm-5.0.1.RELEASE.jar
    │ ├─spring-oxm-5.0.1.RELEASE.jar
    │ ├─spring-test-5.0.1.RELEASE.jar
    │ ├─spring-tx-5.0.1.RELEASE.jar
    │ ├─spring-web-5.0.1.RELEASE.jar
    │ ├─spring-webflux-5.0.1.RELEASE.jar
    │ ├─spring-webmvc-5.0.1.RELEASE.jar
    │ └─spring-websocket-5.0.1.RELEASE.jar
    ├─springmvc-config.xml
    └─web.xml

使用数组 List Set作为数据源

User.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package org.fkit.domain;

import java.io.Serializable;
import java.util.List;

// 域对象,实现序列化接口
public class User
implements Serializable
{

private static final long serialVersionUID = 1L;
// 课程列表
private List<String> courses;

public User()
{
super();
}

public List<String> getCourses()
{
return courses;
}

public void setCourses(List<String> courses)
{
this.courses = courses;
}
}

UserController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package org.fkit.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.fkit.domain.Dept;
import org.fkit.domain.Employee;
import org.fkit.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class UserController {

@GetMapping(value = "/checkboxesForm")
public String registerForm(Model model)
{
User user = new User();
// 为集合变量courses添加“JAVAEE”和“Spring”,页面的checkbox复选框这两项会被选中
List<String> list = new ArrayList<String>();
list.add("JAVAEE");
list.add("Spring");
user.setCourses(list);
// 页面展现的可供选择的复选框内容courseList
List<String> courseList = new ArrayList<String>();
courseList.add("JAVAEE");
courseList.add("Mybatis");
courseList.add("Spring");
// model中添加属性user和courseList
model.addAttribute("user", user);
model.addAttribute("courseList", courseList);
// 返回视图的路径
return "checkboxesForm";
}
@GetMapping(value = "/checkboxesForm2")
public String registerForm2(Model model)
{
User user = new User();
// 为集合变量courses添加“JAVAEE”和“Spring”,页面的checkbox复选框这两项会被选中
List<String> list = new ArrayList<String>();
list.add("1");
list.add("3");
user.setCourses(list);
// 页面展现的可供选择的复选框内容courseList
Map<String, String> courseMap = new HashMap<String, String>();
courseMap.put("1", "JAVAEE");
courseMap.put("2", "Mybatis");
courseMap.put("3", "Spring");
// model中添加属性user和courseList
model.addAttribute("user", user);
model.addAttribute("courseMap", courseMap);
// 返回视图的路径
return "checkboxesForm2";
}

@GetMapping(value = "/checkboxesForm3")
public String registerForm3(Model model)
{
Employee employee = new Employee();
Dept dept = new Dept(1, "开发部");
// 为集合变量depts添加Dept对象,该对象id=1,name=开发吧,页面的checkbox复选框这一项会被选中
List<Dept> list = new ArrayList<Dept>();
list.add(dept);
employee.setDepts(list);
// 页面展现的可供选择的复选框内容deptList
List<Dept> deptList = new ArrayList<Dept>();
deptList.add(dept);
deptList.add(new Dept(2, "销售部"));
deptList.add(new Dept(3, "财务部"));
// model中添加属性employee和deptList
model.addAttribute("employee", employee);
model.addAttribute("deptList", deptList);
// 返回视图路径
return "checkboxesForm3";
}

}

UserController类中创建User对象, 并给User对象的courses集合变量添加了“JAVAEE” 和“Spring” 课程。 之后创建了courseList集合变量, 该集合变量的内容作为页面显示的可供选择的复选框内容。 而页面显示的内容如果在courses中存在, 则会被设置为选中状态, 即“JAVAEE” 和“Spring” 内容会默认被选中。

checkboxesForm.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>测试checkboxes标签</title>
</head>
<body>
<h3>form:checkboxes测试</h3>
<!-- modelAttribute="user" 表示当前表单绑定的是model中的user属性 -->
<form:form modelAttribute="user" method="post" action="checkboxesForm">
<table>
<tr>
<td>选择课程:</td>
<!-- items="${courseList}" 表示复选框的 选项列表 是 model中courseList的内容 -->
<!-- path="courses" 表示复选框 勾选的选项 是 表单绑定的user对象的courses成员变量中的内容 -->
<td><form:checkboxes items="${courseList}" path="courses"
delimiter="<br>" /></td>
<!-- delimiter="<br>" 表示每个列表项用换行分隔 -->
</tr>
</table>
</form:form>
</body>
</html>

web.xml文件和springmvc-config.xml文件与之前讲述的一致, 此处不再赘述。

测试

部署CheckboxesTest这个Web应用, 在浏览器中输入如下URL来测试应用:

http://localhost:8080/CheckboxesTest/checkboxesForm

渲染效果

html代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<form id="user" action="checkboxesForm" method="post">
<table>
<tr>
<td>选择课程:</td>
<td><span>
<input id="courses1" name="courses" type="checkbox" value="JAVAEE" checked="checked" />
<label for="courses1">JAVAEE</label>
</span>
<span>
<br>
<input id="courses2" name="courses" type="checkbox" value="Mybatis" />
<label for="courses2">Mybatis</label>
</span>
<span>
<br>
<input id="courses3" name="courses" type="checkbox" value="Spring" checked="checked" />
<label for="courses3">Spring</label>
</span>
<input type="hidden" name="_courses" value="on" />
</td>
</tr>
</table>
</form>

显示效果

展开/折叠
选择课程:

上面介绍的情况是使用List集合作为显示复选框项的数据源, 我们可以看到, 复选框所呈现出来的标签label和该复选框的值是一样的。 使用ArraySet作为数据源也是这样。

<span>
    <input id="courses1" name="courses" type="checkbox" value="JAVAEE" checked="checked" />
    <label for="courses1">JAVAEE</label>
</span>

使用Map作为数据源

那么如果要让checkboxes呈现出来的labelvalue不同应该怎么做呢? 这时我们可以使用Map作为数据源。 使用Map作为checkboxesitems属性的数据源时,Map集合的key将作为真正的复选框的value, 而Map集合的value将作为label进行显示。 当使用Map作为checkboxesitems属性的数据源时我们绑定的表单对象属性的类型可以是Array、 集合和Map, 这种情况下就是判断items Map中是否含有对应的key来决定当前的复选框是否处于选中状态。

请求处理方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@GetMapping(value = "/checkboxesForm2")
public String registerForm2(Model model)
{
User user = new User();
// 为集合变量courses添加“JAVAEE”和“Spring”,页面的checkbox复选框这两项会被选中
List<String> list = new ArrayList<String>();
list.add("1");
list.add("3");
user.setCourses(list);
// 页面展现的可供选择的复选框内容courseList
Map<String, String> courseMap = new HashMap<String, String>();
courseMap.put("1", "JAVAEE");
courseMap.put("2", "Mybatis");
courseMap.put("3", "Spring");
// model中添加属性user和courseList
model.addAttribute("user", user);
model.addAttribute("courseMap", courseMap);
// 返回视图的路径
return "checkboxesForm2";
}

registerForm2方法中, 提供给页面显示的可供选择的复选框列表内容courseMap是一个Map, 而user对象的courses集合变量中保存的正是courseMap中的key, 它用来决定页面的复选框是否处于选中状态。

测试

在浏览器中输入如下URL来测试应用:

http://localhost:8080/CheckboxesTest/checkboxesForm2

渲染效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<form id="user" action="checkboxesForm2" method="post">
<table>
<tr>
<td>选择课程:</td>
<td>
<span>
<input id="courses1" name="courses" type="checkbox" value="1" checked="checked" />
<label for="courses1">JAVAEE</label>
</span>
<span>
<br>
<input id="courses2" name="courses" type="checkbox" value="2" />
<label for="courses2">Mybatis</label>
</span>
<span>
<br>
<input id="courses3" name="courses" type="checkbox" value="3" checked="checked" />
<label for="courses3">Spring</label>
</span>
<input type="hidden" name="_courses" value="on" />
</td>
</tr>
</table>
</form>

查看源代码, 发现checkboxvaluelabel不同了,value的值正是Mapkey, 而label的值正是Mapvalue

<span>
    <input id="courses1" name="courses" type="checkbox" value="1" checked="checked" />
    <label for="courses1">JAVAEE</label>
</span>

渲染效果

选择课程:

itemLabel和itemValue属性

当使用Array或者集合作为数据源, 且里面的元素都是一个domain对象时, 还可以使用checkboxes标签的itemLabelitemValue属性来表示, 使用数组或者集合中元素对象的哪一个属性作为需要呈现的单选框的labelvalue

Dept.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package org.fkit.domain;
import java.io.Serializable;
public class Dept
implements Serializable
{
private static final long serialVersionUID = 1L;
// 编号
private Integer id;
// 姓名
private String name;
public Dept()
{
super();
// TODO Auto-generated constructor stub
}
public Dept(Integer id, String name)
{
super();
this.id = id;
this.name = name;
}
// 此处省略getter和setter方法,请自己补上
}

Dept类表示一个部门, 有idname两个属性。 之后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package org.fkit.domain;
import java.io.Serializable;
import java.util.List;
public class Employee
implements Serializable
{
private static final long serialVersionUID = 1L;
// 部门列表
private List<Dept> depts;
public List<Dept> getDepts()
{
return depts;
}
public void setDepts(List<Dept> depts)
{
this.depts = depts;
}

Employee.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package org.fkit.domain;

import java.io.Serializable;
import java.util.List;

public class Employee
implements Serializable
{

private static final long serialVersionUID = 1L;
// 部门列表
private List<Dept> depts;

public List<Dept> getDepts()
{
return depts;
}

public void setDepts(List<Dept> depts)
{
this.depts = depts;
}

}

Employee类提供了一个List集合属性depts, 用于绑定数据

checkboxesForm3.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>测试checkboxes标签</title>
</head>
<body>
<h3>form:checkboxes测试</h3>
<%-- 绑定到model中的employee属性(Employee对象) --%>
<form:form modelAttribute="employee" method="post"
action="checkboxesForm3">
<table>
<tr>
<td>选择部门:</td>
<td>
<%-- items中存放的是所有的选项列表 --%>
<%-- path表示要勾选上的选项 --%>
<%-- itemLabel="name" 使用employee的name属性作为label --%>
<%-- itemValue="id" 使用employee对象的id属性作为input标签的value值 --%>
<form:checkboxes items="${deptList}" path="depts"
itemLabel="name" itemValue="id" />
</td>
</tr>
</table>
</form:form>
</body>
</html>

请求处理方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@GetMapping(value = "/checkboxesForm3")
public String registerForm3(Model model)
{
Employee employee = new Employee();
Dept dept = new Dept(1, "开发部");
// 为集合变量depts添加Dept对象,该对象id=1,name=开发吧,页面的checkbox复选框这一项会被选中
List<Dept> list = new ArrayList<Dept>();
list.add(dept);
employee.setDepts(list);
// 页面展现的可供选择的复选框内容deptList
List<Dept> deptList = new ArrayList<Dept>();
deptList.add(dept);
deptList.add(new Dept(2, "销售部"));
deptList.add(new Dept(3, "财务部"));
// model中添加属性employee和deptList
model.addAttribute("employee", employee);
model.addAttribute("deptList", deptList);
// 返回视图路径
return "checkboxesForm3";
}

测试

在浏览器中输入如下URL来测试应用:

http://localhost:8080/CheckboxesTest/checkboxesForm3

渲染效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<form id="employee" action="checkboxesForm3" method="post">
<table>
<tr>
<td>选择部门:</td>
<td>
<span>
<input id="depts1" name="depts" type="checkbox" value="1" checked="checked" />
<label for="depts1">开发部</label>
</span>
<span>
<input id="depts2" name="depts" type="checkbox" value="2" />
<label for="depts2">销售部</label>
</span>
<span>
<input id="depts3" name="depts" type="checkbox" value="3" />
<label for="depts3">财务部</label>
</span>
<input type="hidden" name="_depts" value="on" />
</td>
</tr>
</table>
</form>
选择部门:

分析

可以看到, 从集合中传出来的Dept对象的name作为label显示,id作为value显示:

//Dept dept = new Dept(1, "开发部");
<span>
    <input id="depts1" name="depts" type="checkbox" value="1" checked="checked" />
    <label for="depts1">开发部</label>
</span>

4.1.6 checkbox标签

Spring MVCcheckbox标签会被渲染为一个类型为checkbox的普通HTML input标签。
checkbox标签可使用如表4.7所示的属性。 表4.7中列出的只是Spring MVCcheckbox标签的常用属性, 并没有包含HTML中的相关属性。

属性 描述
cssClass 义要应用到被渲染的checkbox元素的CSS
cssStyle 义要应用到被渲染的checkbox元素的CSS样式
cssErrorClass 定义要应用到被渲染的checkbox元素的CSS类,如果bound属性中包含错误,则覆盖cssClass属性值
htmlEscape boolean值,表示被渲染的值是否应该进行HTML转义
path 要绑定的属性路径
label 要作为label被渲染的复选框的值

1. 绑定boolean数据

checkbox绑定的是一个boolean数据时,checkbox的状态跟被绑定的boolean数据的状态是一样的, 即为true时复选框选中, 为false时复选框不选中。

2. 绑定列表数据

**这里的列表数据包括数组ListSet**。
假设有一个User类,User类有一个类型为List的属性courses。 当我们需要显示该Usercourses时, 可以使用checkbox标签来绑定courses数据进行显示。 当checkbox标签的value属性在我们绑定的列表数据中存在时该checkbox将为选中状态。

示例: checkbox标签的使用

项目结构

展开/折叠
G:\Desktop\随书源码\Spring+Mybatis企业应用实战(第2版)\codes\04\CheckboxTest
├─src\
│ └─org\
│   └─fkit\
│     ├─controller\
│     │ └─UserController.java
│     └─domain\
│       └─User.java
└─WebContent\
  ├─META-INF\
  │ └─MANIFEST.MF
  └─WEB-INF\
    ├─content\
    │ └─checkboxForm.jsp
    ├─lib\
    │ ├─commons-logging-1.2.jar
    │ ├─spring-aop-5.0.1.RELEASE.jar
    │ ├─spring-aspects-5.0.1.RELEASE.jar
    │ ├─spring-beans-5.0.1.RELEASE.jar
    │ ├─spring-context-5.0.1.RELEASE.jar
    │ ├─spring-context-indexer-5.0.1.RELEASE.jar
    │ ├─spring-context-support-5.0.1.RELEASE.jar
    │ ├─spring-core-5.0.1.RELEASE.jar
    │ ├─spring-expression-5.0.1.RELEASE.jar
    │ ├─spring-instrument-5.0.1.RELEASE.jar
    │ ├─spring-jcl-5.0.1.RELEASE.jar
    │ ├─spring-jdbc-5.0.1.RELEASE.jar
    │ ├─spring-jms-5.0.1.RELEASE.jar
    │ ├─spring-messaging-5.0.1.RELEASE.jar
    │ ├─spring-orm-5.0.1.RELEASE.jar
    │ ├─spring-oxm-5.0.1.RELEASE.jar
    │ ├─spring-test-5.0.1.RELEASE.jar
    │ ├─spring-tx-5.0.1.RELEASE.jar
    │ ├─spring-web-5.0.1.RELEASE.jar
    │ ├─spring-webflux-5.0.1.RELEASE.jar
    │ ├─spring-webmvc-5.0.1.RELEASE.jar
    │ └─spring-websocket-5.0.1.RELEASE.jar
    ├─springmvc-config.xml
    └─web.xml

User.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package org.fkit.domain;

import java.io.Serializable;
import java.util.List;

// 域对象,实现序列化接口
public class User
implements Serializable
{
private static final long serialVersionUID = 1L;
private boolean reader;
private List<String> courses;
public User()
{
super();
}
public boolean isReader()
{
return reader;
}
public void setReader(boolean reader)
{
this.reader = reader;
}
public List<String> getCourses()
{
return courses;
}
public void setCourses(List<String> courses)
{
this.courses = courses;
}
}

解析

User类中有一个boolean类型的变量readerList<String>类型的变量courses, 分别用来测试checkbox绑定boolean数据和绑定列表数据。

UserController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package org.fkit.controller;

import java.util.ArrayList;
import java.util.List;
import org.fkit.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class UserController {
@GetMapping(value = "/checkboxForm")
public String registerForm(Model model)
{
User user = new User();
// boolean变量的值为true,则checkbox默认选中
user.setReader(true);
// boolean变量的值为false,则checkbox默认选中
// user.setReader(false);
List<String> list = new ArrayList<String>();
// value="JavaEE"的复选框将被选中
list.add("JavaEE");
// value="Mybatis"的复选框将被选中
list.add("Mybatis");
// value="xxxx"的复选框将被选中
list.add("xxxx");
user.setCourses(list);
// model中添加属性command,值是user对象
model.addAttribute("user", user);
return "checkboxForm";
}
}

代码分析

UserController中创建了User对象, 并分别设置了变量readercourses的值, 并将它们添加到Model中和页面进行绑定。

checkboxForm.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>测试checkbox标签</title>
</head>
<body>
<h3>form:checkbox测试</h3>
<form:form modelAttribute="user" method="post" action="checkboxForm">
<table>
<tr>
<td>选择课程:</td>
<td><form:checkbox path="courses" value="JavaEE" label="JavaEE" /><br>
<form:checkbox path="courses" value="Mybatis" label="Mybatis" /><br>
<form:checkbox path="courses" value="Spring" label="Spring" /><br>
<!-- 浏览器将会显示lable标签中的内容 --> <form:checkbox path="courses"
value="JDBC" label="xxxx" /><br></td>
</tr>
</table>
<form:checkbox path="reader" value="false" />已经阅读相关协议
</form:form>
</body>
</html>

web.xml文件和springmvc-config.xml文件与之前讲述的一致, 此处不再赘述。

测试

部署CheckboxTest这个Web应用, 在浏览器中输入如下URL来测试应用:

http://localhost:8080/CheckboxTest/checkboxForm

渲染效果

1
2
3
4
5
6
7
8
9
10
11
12
13
<h3>form:checkbox测试</h3>
<form id="user" action="checkboxForm" method="post">
<table>
<tbody><tr>
<td>选择课程:</td>
<td><input id="courses1" name="courses" type="checkbox" value="JavaEE" checked="checked"><label for="courses1">JavaEE</label><input type="hidden" name="_courses" value="on"><br>
<input id="courses2" name="courses" type="checkbox" value="Mybatis" checked="checked"><label for="courses2">Mybatis</label><input type="hidden" name="_courses" value="on"><br>
<input id="courses3" name="courses" type="checkbox" value="Spring"><label for="courses3">Spring</label><input type="hidden" name="_courses" value="on"><br>
<!-- 浏览器将会显示lable标签中的内容 --> <input id="courses4" name="courses" type="checkbox" value="JDBC"><label for="courses4">xxxx</label><input type="hidden" name="_courses" value="on"><br></td>
</tr>
</tbody></table>
<input id="reader1" name="reader" type="checkbox" value="true" checked="checked"><input type="hidden" name="_reader" value="on">已经阅读相关协议
</form>

4.1.3 password标签

渲染成密码框

Spring MVCpassword标签会被渲染为一个类型为password的普通HTML input标签。password标签的用法跟input标签相似, 也能绑定表单数据, 只是它生成的是一个密码框, 并且多了一个showPassword属性。

属性

password标签可使用如表4.4所示的属性。 表4.4中列出的只是Spring MVCpassword标签的常用属性, 并没有包含HTML的相关属性。

属性 描述
cssClass 定义要应用到被渲染的password元素的CSS
cssStyle 定义要应用到被渲染的password元素的CSS样式
cssErrorClass 定义要应用到被渲染的password元素的CSS类,如果bound属性中包含错误,则覆盖cssClass属性值
htmlEscape boolean值,表示被渲染的值是否应该进行HTML转义
path 要绑定的属性路径
showPassword 表示是否应该显示或遮盖密码,默认值为false

示例代码

下面是一个password标签的例子:

1
<form:password path="password"/>

上面的代码运行时password标签会被渲染成下面的HTML元素:

1
<input id="password" name="password" type="password" value=""/>

4.1.4 hidden标签

渲染成隐藏域

Spring MVChidden标签会被渲染为一个类型为hidden的普通HTML input标签。

用于绑定表单数据

其用法跟input标签相似, 也能绑定表单数据, 只是它生成的是一个隐藏域, 没有可视的外观。
hidden标签可使用如表 4.5 所示的属性。 表 4.5 中列出的只是Spring MVChidden标签的常用属性, 并没有包含HTML的相关属性。

属性

属性 描述
htmlEscape boolean值,表示被渲染的值是否应该进行HTML转义
path 要绑定的属性路径

示例代码

下面是一个hidden标签的例子:

1
<form:hidden path="id"/>

上面的代码运行时hidden标签会被渲染成下面的HTML元素:

1
<input id="id" name="id" type="hidden" value=""/>

4.1.5 textarea标签

渲染为多行文本框

Spring MVCtextarea标签会被渲染为一个类型为textareaHTML标签。textarea是一个支持多行输入的HTML元素。

属性

textarea标签可使用如表4.6所示的属性。 表4.6中列出的只是Spring MVCtextarea标签的常用属性, 并没有包含HTML的相关属性。

属性 描述
cssClass 定义要应用到被渲染的textarea元素的CSS
cssStyle 定义要应用到被渲染的textarea元素的CSS样式
cssErrorClass 定义要应用到被渲染的textarea元素的CSS类,如果bound属性中包含错误,则覆盖cssClass属性值
htmlEscape boolean值,表示被渲染的值是否应该进行HTML转义
path 要绑定的属性路径

示例代码

下面是一个textarea标签的例子:

1
<form:textarea path="remark" rows="5" cols="20"/>

上面的代码运行时textarea标签会被渲染成下面的HTML元素:

1
<textarea id="remark" name="remark" rows="5" cols="20"></textarea>