5.6.4 setTimeZone标签

setTimeZone标签用于将指定时区保存在一个有界变量或者时间配置变量中。setTimeZone的语法如下:

1
2
<fmt:setTimeZone value="timeZone" [var="varName"]
[scope="{page|request|session|application}"]/>

setTimeZone标签的属性

属性 类型 描述
value+ 字符串或java.util.TimeZone 时区
var 字符串 保存类型为java.util.TimeZone的时区的有界变量
scope 字符串 var的范围或者时区配置变量

5.6.3 timeZone标签

timeZone标签用于定义时区,使其body content中的时间信息按指定时区进行格式化或者解析。其语法如下:

1
2
3
<fmt:timeZone value="timeZone">
body content
</fmt:timeZone>

body contentJSP

timeZone标签的属性

timeZone只有一个value属性,value属性的属性值可以是类型为String或者java.util.TimeZone的动态值。

美国和加拿大时区的值

美国和加拿大时区的值如下表所示:

缩写 全名 时区
NST 纽芬兰标准时间 UTC-3:30
NDT 纽芬兰夏时制 UTC-2:30
AST 大西洋标准时间 UTC-4
ADT 大西洋夏时制 UTC-3
EST 东部标准时间 UTC-5
EDT 东部夏时制 UTC-4
ET 东部时间,如ESTEDT *
CST 中部标准时间 UTC-6
CDT 中部夏时制 UTC-5
CT 中部时间,如CSTCDT *
MST 山地标准时间 UTC-7
MDT 山地夏时制 UTC-6
MT 山地时间,如MSTMDT *
PST 太平洋标准时间 UTC-8
PDT 太平洋夏时制 UTC-7
PT 太平洋时间,如PSTPDT *
AKST 阿拉斯加标准时间 UTC-9
AKDT 阿拉斯加夏时制 UTC-8
HST 夏威夷标准时间 UTC-10

如果value属性为null或者empty,则使用GMT时区。

实例

设置请求对象中设置属性

1
2
3
4
<%@page import="java.util.Date"%>
<%
request.setAttribute("now", new Date());
%>

使用timeZone标签设置时区

1
2
3
4
5
6
7
8
9
10
11
12
13
<fmt:timeZone value="GMT+1:00">
<!-- 使用该时区格式化日期和时间 -->
<fmt:formatDate value="${now}" type="both" dateStyle="full"
timeStyle="full" />
</fmt:timeZone><br>
<fmt:timeZone value="HST">
<fmt:formatDate value="${now}" type="both" dateStyle="full"
timeStyle="full" />
</fmt:timeZone><br>
<fmt:timeZone value="CST">
<fmt:formatDate value="${now}" type="both" dateStyle="full"
timeStyle="full" />
</fmt:timeZone><br>

运行结果:

1
2
3
2019年4月6日 星期六 上午07时48分22秒 GMT+01:00
2019年4月5日 星期五 下午08时48分22秒 HST
2019年4月6日 星期六 上午01时48分22秒 CDT

小结

timeZone标签的标签体中使用formatDate标签,可以得到该时区对应的格式化时间。

完整代码

timeZoneTest.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
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>timeZone Test</title>
</head>
<body>
<%@page import="java.util.Date"%>
<%
request.setAttribute("now", new Date());
%>
<fmt:timeZone value="GMT+1:00">
<!-- 使用该时区格式化日期和时间 -->
<fmt:formatDate value="${now}" type="both" dateStyle="full"
timeStyle="full" />
</fmt:timeZone><br>
<fmt:timeZone value="HST">
<fmt:formatDate value="${now}" type="both" dateStyle="full"
timeStyle="full" />
</fmt:timeZone><br>
<fmt:timeZone value="CST">
<fmt:formatDate value="${now}" type="both" dateStyle="full"
timeStyle="full" />
</fmt:timeZone><br>
</body>
</html>

5.6.2 formatDate标签

引用格式化标签库

首先要在JSP页面中使用taglib指令引入格式化标签库,如下所示:

1
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

formatDate标签语法格式

formatDate标签用于格式化日期,其语法如下:

1
2
3
4
5
6
7
8
9
<fmt:formatDate value="date"
[type="{time|date|both}"]
[dateStyle="{default|short|medium|long|full}"]
[timeStyle="{default|short|medium|long|full}"]
[pattern="customPattern"]
[timeZone="timeZone"]
[var="varName"]
[scope="{page|request|session|application}"]
/>

formatDate标签的属性

属性 类型 描述
value+ java.util.Date 要格式化的日期或时间
type+ 字符串 说明要格式化的是时间、日期,还是时间与日期元件
dataStyle+ 字符串 预定义日期的格式化样式,遵循java.text.DateFormat中定义的语义
timeStyle+ 字符串 预定义时间的格式化样式,遵循java.text.DateFormat中定义的语义
pattern+ 字符串 定制格式化样式
timezone+ 字符串或java.util.TimeZone 定义用于显示时间的时区
var 字符串 将输出结果存为字符串的有界变量名称
scope 字符串 var的范围
timeZone属性的可能值,请查看5.6.3节。

实例

设置日期属性

下面创建一个Date对象.

1
2
3
4
<%@page import="java.util.Date"%>
<%
request.setAttribute("now", new Date());
%>

格式化日期

下列代码利用formatDate标签格式化有界变量now引用的java.util.Date对象:

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
<h2>格式化日期</h2>
<table>
<tr>
<th>dateStyle</th>
<th>效果</th>
</tr>
<tr>
<td>Default:</td>
<td><fmt:formatDate value="${now}" /></td>
</tr>
<tr>
<td>Short:</td>
<!-- type属性没有,则默认为格式化日期
使用预定义日期的格式化样式short -->
<td><fmt:formatDate value="${now}"
dateStyle="short" /></td>
</tr>
<tr>
<td>Medium:</td>
<!-- 使用预定义日期的格式化样式medium -->
<td><fmt:formatDate value="${now}"
dateStyle="medium" /></td>
</tr>
<tr>
<td>Long:</td>
<!-- 使用预定义日期的格式化样式long -->
<td><fmt:formatDate value="${now}"
dateStyle="long" /></td>
</tr>
<tr>
<td>Full:</td>
<!-- 使用预定义日期的格式化样式full -->
<td><fmt:formatDate value="${now}"
dateStyle="full" /></td>
</tr>
</table>

运行结果:
这里有一张图片

格式化时间

下面的formatDate标签用于格式化时间:

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
<h2>格式化时间</h2>
<!-- type属性为time则格式化时间 -->
<table>
<tr>
<th>timeStyle</th>
<th>效果</th>
</tr>
<tr>
<td>Default:</td>
<td><fmt:formatDate type="time"
value="${now}" /></td>
</tr>
<tr>
<td>Short:</td>
<td><fmt:formatDate type="time" value="${now}"
timeStyle="short" /></td>
</tr>
<tr>
<td>Medium:</td>
<td><fmt:formatDate type="time" value="${now}"
timeStyle="medium" /></td>
</tr>
<tr>
<td>Long:</td>
<td><fmt:formatDate type="time" value="${now}"
timeStyle="long" /></td>
</tr>
<tr>
<td>Full:</td>
<td><fmt:formatDate type="time" value="${now}"
timeStyle="full" /></td>
</tr>
</table>

运行结果:
这里有一张图片

格式化时间和日期

下面的formatDate标签用于格式化日期和时间:

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
<h2>格式化时间和日期</h2>
<table>
<tr>
<th>dateStyle and timeStyle</th>
<th>效果</th>
</tr>
<tr>
<td>Default:</td>
<!-- type属性为both,表示同时格式化时间和日期 -->
<td><fmt:formatDate type="both"
value="${now}" /></td>
</tr>
<tr>
<td>Short date short time:</td>
<td><fmt:formatDate type="both" value="${now}"
dateStyle="short" timeStyle="short" /></td>
</tr>
<tr>
<td>Long date long time format:</td>
<td><fmt:formatDate type="both" value="${now}"
dateStyle="long" timeStyle="long" /></td>
</tr>
<tr>
<td>full date full time format:</td>
<td><fmt:formatDate type="both"
value="${now}" dateStyle="full"
timeStyle="full" /></td>
</tr>
</table>

显示效果:
这里有一张图片

格式化带时区的时间

下面的formatDate标签用于格式化带时区的时间:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<h2>格式化带时区的时间</h2>
<table>
<tr>
<th>timeZone</th>
<th>效果</th>
</tr>
<tr>
<td>Time zone CT:</td>
<td><fmt:formatDate type="time" value="${now}"
timeZone="CT" /></td>
</tr>
<tr>
<td>Time zone HST:</td>
<td><fmt:formatDate type="time" value="${now}"
timeZone="HST" /></td>
</tr>
</table>

运行效果:
这里有一张图片

使用自定义格式来格式化时间和日期

下面的formatDate标签利用定制模式格式化日期和时间:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<h2>使用自定义格式格式化时间和日期</h2>
<table>
<tr>
<th>自定义格式</th>
<th>效果</th>
</tr>
<tr>
<td>dd.MM.yy</td>
<td><fmt:formatDate type="both" value="${now}"
pattern="dd.MM.yy" /></td>
</tr>
<tr>
<td>dd.MM.yyyy</td>
<td><fmt:formatDate type="both" value="${now}"
pattern="dd.MM.yyyy" /></td>
</tr>
</table>

显示效果:
这里有一张图片

5.6 格式化行为

JSTL提供了格式化和解析数字与日期的标签,它们是formatNumberformatDatetimeZonesetTimeZoneparseNumberparseDate

引用格式化标签库

要使用这些标签,首先要在JSP页面中使用taglib指令引入格式化标签库,如下所示:

1
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

如果忘了导入库,则eclipse中会显示如下错误信息:

1
Unknown tag (fmt:formatNumber).

5.6.1 formatNumber标签

formatNumber用于格式化数字。这个标签使你可以根据需要,利用它的各种属性来获得自己想要的格式。formatNumber的语法有两种形式。

第一种形式没有body content

1
2
3
4
5
6
7
8
9
10
11
12
13
<fmt:formatNumber value="numericValue"
[type="{number|currency|percent}"]
[pattern="customPattern"]
[currencyCode="currencyCode"]
[currencySymbol="currencySymbol"]
[groupingUsed="{true|false}"]
[maxIntegerDigits="maxIntegerDigits"]
[minIntegerDigits="minIntegerDigits"]
[maxFractionDigits="maxFractionDigits"]
[minFractionDigits="minFractionDigits"]
[var="varName"]
[scope="{page|request|session|application}"]
/>

第二种形式有body content

1
2
3
4
5
6
7
8
9
10
11
12
13
<fmt:formatNumber [type="{number|currency|percent}"]
[pattern="customPattern"]
[currencyCode="currencyCode"]
[currencySymbol="currencySymbol"]
[groupingUsed="{true|false}"]
[maxIntegerDigits="maxIntegerDigits"]
[minIntegerDigits="minIntegerDigits"]
[maxFractionDigits="maxFractionDigits"]
[minFractionDigits="minFractionDigits"]
[var="varName"]
[scope="{page|request|session|application}"]>
numeric value to be formatted
</fmt:formatNumber>

body contentJSP代码

formatNumber标签的属性

属性 类型 描述
value+ 字符串或数字 要格式化的数字化值
type+ 字符串 说明该值是要被格式化成数字货币,还是百分比。对应的属性值分别为numbercurrencypercent
pattern+ 字符串 定制格式化样式
currencyCode+ 字符串 ISO 4217货币码,仅当type="currency"时使用
currencySymbol+ 字符串 货币符号,仅当type="currency"时使用
groupingUsed+ 布尔 说明输出结果中是否包含组分隔符
maxIntegerDigits+ 整数 规定输出结果的整数部分最多几位数字
minIntegerDigits+ 整数 规定输出结果的整数部分最少几位数字
maxFractionDigits+ 整数 规定输出结果的小数部分最多几位数字
minFractionDigits+ 整数 规定输出结果的小数部分最少几位数字
var 字符串 将输出结果存为字符串的有界变量名称
scope 字符串 var的范围。如果有scope属性,则必须指定var属性

formatNumber标签的用途之一就是将数字格式化成货币。为此,可以利用currencyCode属性来定义一个ISO 4217货币代码。

格式化样式pattern说明

符号 描述
0 代表一位数字
E 使用指数格式
# 代表一位数字,若没有则显示0,前导0和末尾0不显示。
. 小数点
, 数字分组分隔符
; 分隔格式
- 使用默认负数前缀
% 百分数
? 千分数
xxxxxxx 货币符号,使用实际的货币符号代替,如使用$,等等
X 指定可以作为前缀或后缀的字符
' 在前缀或后缀中引用特殊字符

formatNumber的用法范例

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
<!-- 引入格式化标签库 -->
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
......
<!-- 格式化为数字,原样输出 -->
<fmt:formatNumber value="12" type="number" />
<br>
<!-- 格式化为数字,整数部分最少是3位数字 -->
<fmt:formatNumber value="12" type="number" minIntegerDigits="3" />
<br>
<!-- 格式化为数字,小数部分最少是2位数字 -->
<fmt:formatNumber value="12" type="number" minFractionDigits="2" />
<br>
<!-- 使用自定义格式,保留小数掉后三位 -->
<!-- `0`代表一位数字 -->
<!-- `.`小数点 -->
<fmt:formatNumber value="123456.78" pattern=".000" />
<br>
<!-- `#`代表一位数字,若没有则显示0,前导0和末尾0不显示。 -->
<!-- `,`数字分组分隔符 -->
<fmt:formatNumber value="123456.78" pattern="#,#00.0#" />
<br>
<!-- 格式化为货币 -->
<fmt:formatNumber value="12" type="currency" />
<br>
<!-- 设置地区为美国 -->
<fmt:setLocale value="en_US"/>
<!-- 格式化为货币,取决于默认地区-->
<fmt:formatNumber value="12" type="currency"/>
<br>
<!-- 格式化为百分数 -->
<fmt:formatNumber value="0.12" type="percent" />
<br>
<!-- 格式化为百分数,百分数小数点后面最少要有两位 -->
<fmt:formatNumber value="0.125" type="percent" minFractionDigits="2" />
<br>

结果如下:

1
2
3
4
5
6
7
8
9
12
012
12.00
123456.780
123,456.78
¥12.00
$12.00
12%
12.50%

5.5.2 forTokens标签

forTokens标签用于遍历以特定分隔符隔开的令牌,其语法如下:

1
2
3
4
5
<c:forTokens items="stringOfTokens" delims="delimiters"
[var="varName"] [varStatus="varStatusName"]
[begin="begin"] [end="end"] [step="step"]>
body content
</c:forTokens>

标签体body content中的代码是JSP代码。

forTokens标签的属性

属性 类型 描述
var 字符串 引用遍历的当前项目的有界变量名称
items+ 支持的任意类型 要遍历的token字符串
varStatus 字符串 保存遍历状态的有界变量名称。类型值为javax.servlet.jsp.jstl.core.LoopTagStatus.
begin+ 整数 遍历的起始索引,默认为0。如有指定,begin的值必须大于或者等于0
end+ 整数 遍历的终止索引,默认为0
step+ 整数 遍历将只处理间隔指定steptoken,从第一个token开始。如有指定,step的值必须大于或者等于1
delims+ 字符串 一组分隔符

demo

下面是一个forTokens范例:

1
2
3
4
5
<!-- 要遍历的字符串为:`Argentina,Brazil,Chile`,分割符为`,` -->
<c:forTokens var="item" items="Argentina,Brazil,Chile"
delims=",">
<c:out value="${item}"/><br/>
</c:forTokens>

代码详解:
上述标签中,要遍历的字符串为:Argentina,Brazil,Chile,分割符为,:
运行结果:

1
2
3
Argentina
Brazil
Chile

5.5 遍历行为

当需要无数次地遍历一个对象集合时,遍历行为就很有帮助。JSTL提供了forEachforTokens两个执行遍历行为的标签:这两个标签将在接下来的小节中讨论。

5.5.1 forEach标签

forEach标签会无数次地反复遍历body content或者对象集合。可以被遍历的对象包括java.util.Collectionjava.util.Map的所有实现类,以及对象数组或者主类型。也可以遍历java.util.Iteratorjava.util.Enumeration,但不应该在多个行为中使用Iterator或者Enumeration,因为无法重置Iterator或者Enumeration

形式1 重复执行标签体

forEach标签的语法有两种形式。第一种形式是固定次数地重复body content

1
2
3
4
<c:forEach [var="varName"] begin="begin" 
end="end" step="step">
body content
</c:forEach>

形式2 遍历集合

第二种形式用于遍历对象集合:

1
2
3
4
5
<c:forEach items="collection" [var="varName"] 
[varStatus="varStatusName"] [begin="begin"]
[end="end"] [step="step"]>
body content
</c:forEach>

forEach标签的标签体body content之中的代码时JSP代码.

forEach标签的属性

属性 类型 描述
var 字符串 引用遍历的当前项目的有界变量名称
items+ 支持的任意类型 遍历的对象集合
varStatus 字符串 保存遍历状态的有界变量名称。类型值为javax.servlet.jsp.jstl.core.LoopTagStatus
begin+ 整数 如果指定items,遍历将从指定索引处的项目开始,例如,集合中第一个项目的索引为0。如果没有指定items,遍历将从设定的索引值开始。如果指定,begin的值必须大于或者等于0
end+ 整数 如果指定items,遍历将在(含)指定索引处的项目结束。如果没有指定items,遍历将在索引到达指定值时结束
step+ 整数 遍历将只处理间隔指定step的项目,从第一个项目开始。在这种情况下,step的值必须大于或者等于1
对于每一次遍历,forEach标签都将创建一个有界变量,变量名称通过var属性定义。这个有界变量只存在于开始和关闭的forEach标签之间,一到关闭的forEach标签前,它就会被删除。

实例

begin end属性

例如,下列的forEach标签将显示“1 2 3 4 5 ”。

1
2
3
<c:forEach var="x" begin="1" end="5">
<c:out value="${x}" />&nbsp;
</c:forEach>

step属性

1
2
3
<c:forEach var="x" begin="1" end="10" step="2">
<c:out value="${x}" />&nbsp;
</c:forEach>

运行结果:1 3 5 7 9

遍历有界变量

下面的forEach标签将遍历有界变量addressphones属性:

1
2
3
<c:forEach var="phone" items="${address.phones}">
${phone}"<br/>
</c:forEach>

在本例中,有界变量命名为phoneforEach标签中的EL表达式用于显示phone的值。

获取遍历的次数

forEach标签有一个类型为javax.servlet.jsp.jstl.core.LoopTagStatus的变量varStatusLoopTagStatus接口带有count属性,它当前遍历的“次数”。第一次遍历时,status.count值1;第二次遍历时,status.count值为2,依次类推。测试status.count%2的余数,可以知道该标签当前遍历到的是偶数编号的元素,还是奇数编号的元素。

forEach标签遍历ArrayList

app05a应用程序中的BookController类和BookList.jsp页面为例。BookController类调用了一个service方法,返回一个Book对象List

Book类

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 app05a.model;
public class Book {
//书号
private String isbn;
//书名
private String title;
//价钱
private double price;
public Book(String isbn, String title, double price) {
this.isbn = isbn;
this.title = title;
this.price = price;
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}

BooksServlet

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
package app05a.servlet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import app05a.model.Book;
@WebServlet(urlPatterns = {"/books"})
public class BooksServlet extends HttpServlet {
private static final int serialVersionUID = -234237;
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {
//书籍列表
List<Book> books = new ArrayList<Book>();
Book book1 = new Book("978-0980839616",
"Java 7: A Beginner's Tutorial", 45.00);
Book book2 = new Book("978-0980331608",
"Struts 2 Design and Programming: A Tutorial",
49.95);
Book book3 = new Book("978-0975212820",
"Dimensional Data Warehousing with MySQL: A "
+ "Tutorial", 39.95);
//添加几本书到书架上
books.add(book1);
books.add(book2);
books.add(book3);
//在请求对象中设置books属性,保存书籍列表
request.setAttribute("books", books);
RequestDispatcher rd =
request.getRequestDispatcher("/books.jsp");
//请求转发
rd.forward(request, response);
}
}

BooksServletdoGet方法中创建了几本书,保存在书籍列表中,然后把书籍列表设置为请求对象的属性.最后再调用book.jsp进行显示.
books.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
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
<%@page contentType="text/html; charset=utf-8" 
pageEncoding="utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>Book List</title>
<style>
table, tr, td {
/* 边框粗1px,实线,边框颜色为 #546e7a */
border: 1px solid #546e7a;
}
</style>
</head>
<body>
Books in Simple Table
<table>
<tr>
<td>ISBN</td>
<td>Title</td>
</tr>
<!-- 遍历请求对象中的books属性所指向的这个ArrayList对象
遍历变量名为book-->
<c:forEach items="${requestScope.books}" var="book">
<tr>
<td>${book.isbn}</td>
<td>${book.title}</td>
</tr>
</c:forEach>
</table>
<br /> Books in Styled Table
<table>
<tr style="background: #0288d1">
<td>ISBN</td>
<td>Title</td>
</tr>
<c:forEach items="${requestScope.books}" var="book"
varStatus="status">
<c:if test="${status.count%2 == 0}">
<tr style="background: #ba68c8">
</c:if>
<c:if test="${status.count%2 != 0}">
<tr style="background: #f06292">
</c:if>
<td>${book.isbn}</td>
<td>${book.title}</td>
</tr>
</c:forEach>
</table>
<br /> ISBNs only:
<c:forEach items="${requestScope.books}" var="book"
varStatus="status">
${book.isbn}<c:if test="${!status.last}">,</c:if>
</c:forEach>
</body>
</html>

其中下面的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<table>
<tr>
<td>ISBN</td>
<td>Title</td>
</tr>
<!-- 遍历请求对象中的books属性所指向的这个ArrayList对象
遍历变量名为book,表示Arraylist中的一个元素,
也就是一个Book对象-->
<c:forEach items="${requestScope.books}" var="book">
<tr>
<!-- 输出book对象isbn编号 -->
<td>${book.isbn}</td>
<!-- 输出book对象的书名 -->
<td>${book.title}</td>
</tr>
</c:forEach>
</table>

使用了forEach标签来遍历保存在请求对象中的books属性(ArrayList),显示效果如下图所示:
这里有一张图片

测试forEach的状态对象

varStatus="status"将创建一个名为status的状态数据对象,使用状态数据对象可以获取本次遍历的一些信息.如status.count表示当前遍历的次数.
测试状态对象的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
<table>
<tr style="background: #0288d1">
<td>ISBN</td>
<td>Title</td>
</tr>
<!-- 遍历请求对象中的books属性(ArrayList),
遍历变量为book(表示ArrayList中的一个元素),
并创建名称为status的遍历状态对象.
-->
<c:forEach items="${requestScope.books}" var="book"
varStatus="status">
<!-- 如果循环是偶数的话,使用xxxxx作为该行的背景颜色 -->
<c:if test="${status.count%2 == 0}">
<tr style="background: #ba68c8">
</c:if>
<!-- 如果循环次数是奇数的话,使用yyyyy作为该行的背景颜色 -->
<c:if test="${status.count%2 != 0}">
<tr style="background: #f06292">
</c:if>
<td>${book.isbn}</td>
<td>${book.title}</td>
</tr>
</c:forEach>
</table>

显示效果:
这里有一张图片

最后一个元素

status.last表示最后的最后一个元素,测试代码如下所示:

1
2
3
4
5
6
7
<br /> ISBNs only:
<c:forEach items="${requestScope.books}" var="book"
varStatus="status">
${book.isbn}
<!-- 如果不是最后一个元素则输出逗号作为分隔符 -->
<c:if test="${!status.last}">,</c:if>
</c:forEach>

forEach标签遍历Map

利用forEach还可以遍历Map。要分别利用keyvalue属性引用一个Map key和一个Map值。遍历Map的伪代码如下:

1
2
3
<c:forEach var="mapItem" items="map">
${mapItem.key} : ${mapItem.value}
</c:forEach>

下一个范例展示了forEachMap的结合使用。CityController类将两个Map实例化,并为它们赋予键/值对。第一个Map中的每一个元素都是一个String/String对,第二个Map中的每一个元素则都是一个String/String[]对。

BigCitiesServlet

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
package app05a.servlet;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(
urlPatterns =
{"/bigCities"}
)
public class BigCitiesServlet extends HttpServlet
{
/**
*
*/
private static final long serialVersionUID = -83191871L;
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException,IOException
{
//创建一个Map
Map<String,String> capitals =
new HashMap<String,String>();
capitals.put("Indonesia", "Jakarta");
capitals.put("Malaysia", "Kuala Lumpur");
capitals.put("Thailand", "Bangkok");
//设置为请求对象的属性,并命名为
request.setAttribute("capitals", capitals);
//创建一个Map
Map<String,String[]> bigCities =
new HashMap<String,String[]>();
bigCities.put("Australia",
new String[]{"Sydney","Melbourne","Perth"});
bigCities.put("New Zealand",
new String[]{"Auckland","Christchurch","Wellington"});
bigCities.put("Indonesia",
new String[]{"Jakarta","Surabaya","Medan"});
request.setAttribute("capitals", capitals);
request.setAttribute("bigCities", bigCities);
//请求转发使用JSP显示
RequestDispatcher rd =
request.getRequestDispatcher("/bigCities.jsp");
rd.forward(request, response);
}
}

bigCities.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
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
<%@page contentType="text/html; charset=UTF-8"
pageEncoding="utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core"
prefix="c"%>
<html>
<head>
<title>Big Cities</title>
<style>
table, tr, td {
border: 1px solid #aaee77;
padding: 3px;
}
</style>
</head>
<body>
Capitals
<table>
<tr style="background: #448755; color: white;
font-weight: bold">
<td>Country</td>
<td>Capital</td>
</tr>
<!-- 遍历请求对象中的 capitals属性 -->
<c:forEach items="${requestScope.capitals}"
var="mapItem">
<tr>
<!-- 取出map的key -->
<td>${mapItem.key}</td>
<!-- 取出对应的value -->
<td>${mapItem.value}</td>
</tr>
</c:forEach>
</table>
<br /> Big Cities
<table>
<tr style="background: #448755; color: white;
font-weight: bold">
<td>Country</td>
<td>Cities</td>
</tr>
<!-- 遍历请求对象中的bigCities这个属性(Map)-->
<c:forEach items="${requestScope.bigCities}"
var="mapItem">
<tr>
<td>${mapItem.key}</td>
<!-- 遍历Map的值,也就是String[]数组 -->
<td><c:forEach items="${mapItem.value}"
var="city" varStatus="status">
<!-- 输出逗号作为分隔符,最后元素不输出逗号 -->
${city}<c:if test="${!status.last}">,</c:if>
</c:forEach></td>
</tr>
</c:forEach>
</table>
</body>
</html>

遍历String/String 类型的Map

设置capitals属性

Servlet中设的的capitals请求对象的属性如下所示:

1
2
3
4
5
6
7
8
//创建一个Map
Map<String,String> capitals =
new HashMap<String,String>();
capitals.put("Indonesia", "Jakarta");
capitals.put("Malaysia", "Kuala Lumpur");
capitals.put("Thailand", "Bangkok");
//设置为请求对象的属性,并命名为
request.setAttribute("capitals", capitals);

然后在JSP页面中通过forEach标签遍历该请求对象中的属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Capitals
<table>
<tr style="background: #448755; color: white;
font-weight: bold">
<td>Country</td>
<td>Capital</td>
</tr>
<!-- 遍历请求对象中的 capitals属性 -->
<c:forEach items="${requestScope.capitals}"
var="mapItem">
<tr>
<!-- 取出map的key -->
<td>${mapItem.key}</td>
<!-- 取出对应的value -->
<td>${mapItem.value}</td>
</tr>
</c:forEach>
</table>

显示效果:
这里有一张图片

遍历String/String[]类型的Map

设置请求对象的bigCities属性

1
2
3
4
5
6
7
8
9
10
//创建一个Map
Map<String,String[]> bigCities =
new HashMap<String,String[]>();
bigCities.put("Australia",
new String[]{"Sydney","Melbourne","Perth"});
bigCities.put("New Zealand",
new String[]{"Auckland","Christchurch","Wellington"});
bigCities.put("Indonesia",
new String[]{"Jakarta","Surabaya","Medan"});
request.setAttribute("bigCities", bigCities);

遍历请求对象的bigCities属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<br /> Big Cities
<table>
<tr style="background: #448755;
color: white; font-weight: bold">
<td>Country</td>
<td>Cities</td>
</tr>
<!-- 遍历请求对象中的bigCities这个属性(Map)-->
<c:forEach items="${requestScope.bigCities}"
var="mapItem">
<tr>
<td>${mapItem.key}</td>
<!-- 遍历Map的值,也就是String[]数组 -->
<td><c:forEach items="${mapItem.value}"
var="city" varStatus="status">
<!-- 输出逗号作为分隔符,最后元素不输出逗号 -->
${city}<c:if test="${!status.last}">,</c:if>
</c:forEach></td>
</tr>
</c:forEach>
</table>

显示效果如下:
这里有一张图片

5.4.2 choose、when和otherwise标签

choosewhen标签的作用与Java中的关键字switchcase类似。choose标签中必须嵌有一个或者多个when标签,并且每个when标签都表示一种可以计算和处理的情况。otherwise标签则用于默认的条件块,假如没有任何一个when标签的测试条件结果为true,它就会得到处理。假如是这种情况,otherwise就必须放在最后一个when后。
chooseotherwise标签没有属性。
when标签必须带有定义测试条件的test属性,用来决定是否应该处理body content

实例

举个例子,以下代码是测试参数status的值。如果status的值为full,将显示You are a full member。如果这个值为student,则显示You are a student member。如果status参数不存在,或者它的值既不是full,也不是student,那么这段代码将不显示任何内容:

1
2
3
4
5
6
7
8
<c:choose>
<c:when test="${param.status=='full'}">
You are a full member
</c:when>
<c:when test="${param.status=='student'}">
You are a student member
</c:when>
</c:choose>

下面的例子与前面的例子相似,使用了otherwise标签,如果status参数不存在,或者它的值不是full或者student,则将显示Please register

1
2
3
4
5
6
7
8
9
10
11
<c:choose>
<c:when test="${param.status=='full'}">
You are a full member
</c:when>
<c:when test="${param.status=='student'}">
You are a student member
</c:when>
<c:otherwise>
Please register
</c:otherwise>
</c:choose>

总结

  • choose类似switch
  • when类似case
  • otherwise类似default

5.4 条件行为

条件行为用于处理页面输出取决于特定输入值的情况,这在Java中是利用ifif...elseswitch声明解决的。
JSTL中执行条件行为的有4个标签,即ifchoosewhenotherwise标签。

5.4.1 if标签

if标签是对某一个条件进行测试,假如结果为true,就处理它的body content。测试结果保存在一个Boolean对象中,并创建有界变量来引用这个Boolean对象。利用var属性和scope属性来定义有界变量的名称和范围。

if标签的属性

属性 类型 描述
test+ 布尔 决定是否处理任何现有body content的测试条件
var 字符串 引用测试条件值的有界变量名称;var的类型为Boolean
scope 字符串 var定义的有界变量的范围

if标签 带标签体形式

第二种形式中使用了一个body content

1
2
3
4
<c:if test="testCondition [var="varName"]
[scope="{page|request|session|application}"]>
body content
</c:if>

body content中是JSP代码,当测试条件的结果为true时,就会执行标签体例的JSP代码。

实例

例如,如果找到请求参数user且值为ken,并且找到请求参数password且值为blackcomb,以下if标签将显示“You logged in successfully

1
2
3
4
<!-- param为EL隐式对象 -->
<c:if test="${param.user=='ken' && param.password=='blackcomb'}">
You logged in successfully.
</c:if>

模拟else语句

为了模拟else,下面使用了两个if标签,并使用了相反的条件。例如,如果userpassword参数的值为kenblackcomb,以下代码片断将显示You logged in successfully,否则,将显示Login failed

1
2
3
4
5
6
7
8
<c:if test="${param.user=='ken' && 
param.password=='blackcomb'}">
You logged in successfully.
</c:if>
<c:if test="${!(param.user=='ken' &&
param.password=='blackcomb')}">
Login failed.
</c:if>

if标签 没有标签体形式

1
2
<c:if test="testCondition" var="varName"
[scope="{page|request|session|application}"]/>

在这种情况下,var定义的有界对象一般是通过其他标签在同一个JSP中的后续阶段再进行测试。

实例

下面的if标签是测试userpassword参数值是否分别为kenblackcomb,并将结果保存在页面范围的变量loggedIn中。之后,利用一个EL表达式,如果loggedIn变量值为true,则显示You logged in successfully;如果loggedIn变量值为false,则显示Login failed

1
2
3
4
5
<c:if var="loggedIn"
test="${param.user=='ken' &&
param.password=='blackcomb'}"/>
...
${(loggedIn)? "You logged in successfully" : "Login failed"}

5.3.3 remove标签

remove标签的作用 语法

remove标签用于删除有界变量,其语法如下:

1
2
<c:remove var="varName"
[scope="{page|request|session|application}"]/>

scope属性默认为page
注意,有界变量所引用的对象不能删除。因此,如果另一个有界对象也引用了同一个对象,仍然可以通过另一个有界变量访问该对象。

remove标签的属性

属性 类型 描述
var 字符串 要删除的有界变量的名称
scope 字符串 要删除的有界变量的范围

实例

举个例子,下面的remove标签就是删除了页面范围的变量job

1
<c:remove var="job" scope="page"/>

5.3.2 set标签

set标签的功能

利用set标签,可以完成以下工作:

  • 创建一个字符串和一个引用该字符串的有界变量。
  • 创建一个引用已存在的有界对象的有界变量。
  • 设置有界对象的属性。

如果用set创建有界变量,那么,在该标签出现后的整个JSP页面中都可以使用该变量。

set标签的形式

set标签的语法有4种形式。

形式1

第一种形式用于创建一个有界变量,并用value属性在其中定义一个要创建的字符串或者有界对象:

1
2
<c:set value="value" var="varName"
[scope="{page|request|session|application}"]/>

这里的scope 属性指定了有界变量的范围。默认为page

例如,下面的set标签创建了字符串“Hello World”,并将它赋给新创建的页面范围变量hello

1
<c:set  value="Hello World" var="hello"/>

下面的set 标签则创建了一个名为job的有界变量,它引用请求范围中position所引用的对象。变量job 的范围为page

1
<c:set var="job" value="${requestScope.position}" scope="page"/>

有界对象本身并非保存在HttpServletRequest之中,requestScope.position只是该对象的引用,上面的set标签,将在页面范围创建一个名为job的有界变量,该有界变量是requestScope.position的一个副本,这两者都引用同一个对象.

形式2

第二种形式与第一种形式相似,只是把创建的字符串或者要引用的有界对象放在标签体(body content)中而已.

1
2
3
<c:set var="varName" [scope="{page|request|session|application}"]>
body content
</c:set>

第二种形式允许在标签体body content中有JSP代码。

形式3

第三种形式用于设置有界对象的属性值。使用target属性定义有界对象,property属性指定要设置的属性名称。通过value属性设置有界对象的属性值:

1
<c:set target="target" property="propertyName" value="value"/>

例如,下面的set 标签把有界对象addresscity属性赋值为Tokyo这个字符串:

1
<c:set target="${address}" property="city" value="Tokyo"/>

注意,必须在target属性中用一个EL表达式来引用这个有界对象

形式4

第四种形式与第三种形式相似,只是赋值是通过标签体body content来完成的:

1
2
3
<c:set target="target" property="propertyName">
body content
</c:set>

例如,下面的set标签是将字符串“Beijing”赋予有界对象addresscity属性:

1
<c:set target="${address}" property="city">Beijing</c:set>

set标签的属性说明

属性 类型 描述
value+ 对象 要创建的字符串,或者要引用的有界对象,或者新的属性值
var 字符串 要创建的有界变量
scope 字符串 新创建的有界变量的范围
target+ 对象 其属性要被赋新值的有界对象;这必须是一个JavaBeans实例或者java.util.Map对象
property+ 字符串 要被赋新值的属性名称

表中的加号表示该属性的属性值可以动态生成.