- 内容提要
- 作者简介
- 译者简介
- 前言
- HTTP
- Servlet 和 JSP
- 下载 Spring 或使用 STS 与 Maven/Gradle
- 手动下载 Spring
- 使用 STS 和 Maven/Gradle
- 下载 Spring 源码
- 本书内容简介
- 下载示例应用
- 第 1 章Spring 框架
- 第 2 章模型 2 和 MVC 模式
- 第 3 章Spring MVC 介绍
- 第 4 章基于注解的控制器
- 第 5 章数据绑定和表单标签库
- 第 6 章转换器和格式化
- 第 7 章验证器
- 第 8 章表达式语言
- 第 9 章JSTL
- 第 10 章国际化
- 第 11 章上传文件
- 第 12 章下载文件
- 第 13 章应用测试
- 附录 A Tomcat
- 附录 B Spring Tool Suite 和 Maven
- 附录 C Servlet
- 附录 D JavaServer Pages
- 附录 E 部署描述符
9.5 遍历行为
当需要无数次地遍历一个对象集合时,遍历行为就很有帮助。JSTL 提供了 forEach 和 forTokens 两个执行遍历行为的标签,这两个标签将在接下来的小节中介绍。
9.5.1 forEach 标签
forEach 标签会无数次地反复遍历 body content 或者对象集合。可以遍历的对象包括 java.util.Collection 和 java.util.Map 的所有实现,以及对象数组或者基本类型。也可以遍历 java.util.Iterator 和 java.util.Enumeration,但不应该在多个行为中使用 Iterator 或者 Enumeration,因为无法重置 Iterator 或者 Enumeration。
forEach 标签的语法有两种形式。第一种形式是固定次数地重复 body content。
< c:forEach [var="varName"] begin="begin" end="end" step="step">
body content
< /c:forEach>
第二种形式用于遍历对象集合。
< c:forEach items="collection" [var="varName"]
[varStatus="varStatusName"] [begin="begin"] [end="end"]
[step="step"]>
body content
< /c:forEach>
body content 是 JSP。forEach 标签的属性见表 9.6。
表 9.6 forEach 标签的属性
属性 | 类型 | 描述 |
---|---|---|
var | 字符串 | 引用遍历的当前项目的有界变量名称 |
items+ | 支持的任意类型 | 遍历的对象集合 |
varStatus | 字符串 | 保存遍历状态的有界变量名称。类型值为 javax.servlet.jsp.jstl.core. LoopTagStatus |
begin+ | 整数 | 如果指定 items,遍历将从指定索引处的项开始,例如,集合中第一项的索引为 0。如果没有指定 items,遍历将从设定的索引值开始。如果指定,begin 的值必须大于或者等于 0 |
end+ | 整数 | 如果指定 items,遍历将在(含)指定索引处的项结束。如果没有指定 items,遍历将在索引到达指定值时结束 |
step+ | 整数 | 遍历将只处理间隔指定 step 的项目,从第一项开始。在这种情况下,step 的值必须大于或者等于 1 |
例如,下列的 forEach 标签将显示“1,2,3,4,5”。
<c:forEach var="x" begin="1" end="5">
<c:out value="${x}"/>,
</c:forEach>
下面的 forEach 标签将遍历有界变量 address 的 phones 属性:
<c:forEach var="phone" items="${address.phones}">
${phone}"<br/>
</c:forEach>
对于每一次遍历,forEach 标签都将创建一个有界变量,变量名称通过 var 属性定义。在本例中,有界变量命名为 phone。forEach 标签中的 EL 表达式用于显示 phone 的值。这个有界变量只存在于开始和结束的 forEach 标签之间,一到结束的 forEach 标签前,它就会被删除。
forEach 标签有一个类型为 javax.servlet.jsp.jstl.core.LoopTagStatus 的变量 varStatus。LoopTagStatus 接口带有 count 属性,它返回当前遍历的“次数”。第一次遍历时,status.count 值为 1;第二次遍历时,Status.count 值为 2,依此类推。通过测试 status.count%2 的余数,可以知道该标签正在处理的是偶数编号的元素,还是奇数编号的元素。
以 iterator 应用程序中的 BookServlet 类和 BookList.jsp 页面为例。如清单 9.5 所示,BookServer 类在其 doGet 方法中,创建了 3 个 Book 对象,并放入到一个 List 对象中,并将该 List 对象存入 ServletRequest 属性中,最后转到 books.jsp 页面,该页面会通过 forEach 标签遍历图书集合。Book 类如清单 9.6 所示。
清单 9.5 Books Servlet 类
package 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", BigDecimal.valueOf(45.00)); Book book2 = new Book("978-0980331608", "Struts 2 Design and Programming: A Tutorial", BigDecimal.valueOf(49.95)); Book book3 = new Book("978-0975212820", "Dimensional Data Warehousing with MySQL: A Tutorial", BigDecimal.valueOf(39.95)); books.add(book1); books.add(book2); books.add(book3); request.setAttribute("books", books); RequestDispatcher rd = request.getRequestDispatcher("/books.jsp"); rd.forward(request, response); } }
清单 9.6 Book 类
package domain;
import java.math.BigDecimal;
public class Book {
private String isbn;
private String title;
private BigDecimal price;
public Book(String isbn, String title, BigDecimal price) {
this.isbn = isbn;
this.title = title;
this.price = price;
}
// getters and setters not shown
}
清单 9.7 books.jsp 页面
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<title>Book List</title>
<style>table, tr, td {
border: 1px solid brown;
}
</style>
</head>
<body>
Books in Simple Table
<table>
<tr>
<td>ISBN</td>
<td>Title</td>
</tr>
<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:#ababff">
<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:#eeeeff">
</c:if>
<c:if test="${status.count%2 != 0}">
<tr style="background:#dedeff">
</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>
注意,books.jsp 页面显示了图书 3 次,第一次是利用没有 varStatus 属性的 forEach 标签。
<table>
<tr>
<th>ISBN</th>
<th>Title</th>
</tr>
<c:forEach items="${requestScope books}" var="book">
<tr>
<td>${book.isbn}</td>
<td>${book.title}</td>
</tr>
</c:forEach>
</table>
第二次是利用有 varStatus 属性的 forEach 标签来显示,这是为了根据偶数行或奇数行来给表格行设计不同的颜色。
<table>
<tr style="background:#ababff">
<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:#eeeeff">
</c:if>
<c:if test="${status.count%2 != 0}">
<tr style="background:#dedeff">
</c:if>
<td>${book.isbn}</td>
<td>${book.title}</td>
</tr>
</c:forEach>
</table>
最后一个 forEach 用来展示以逗号分隔的 ISBN,status.last 用来避免在文末有逗号。
<c:forEach items="${requestScope.books}" var="book"
varStatus="status">
${book.isbn}<c:if test="${!status.last}">,</c:if>
</c:forEach>
利用以下 URL 可以查看以上范例:
http://localhost:8080/iterator/books
其输出结果与图 9.3 所示的屏幕截图相似。
图 9.3 对 List 使用 forEach
利用 forEach 还可以遍历 Map。要分别利用 key 和 value 属性引用一个 Map key 和一个 Map 值。遍历 Map 的伪代码如下所示:
< c:forEach var="mapItem" items="map">
${mapItem.key} : ${mapItem.value}
< /c:forEach>
清单 9.8 展示了 forEach 与 Map 的结合使用。清单 9.8 中的 BigCitiesServlet 类将两个 Map 实例化,并为它们赋予键/值对。第一个 Map 中的每一个元素都是一个 String/String 对,第二个 Map 中的每一个元素则都是一个 String/String[]对。
清单 9.8 BigCitiesServlet 类
package servlet;
import java.io.IOException;
import java.util.HashMap;
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 = 1L;
@Override
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
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<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);
RequestDispatcher rd =
request.getRequestDispatcher("/bigCities.jsp");
rd.forward(request, response);
}
}
在 doGet 方法的结尾处,servlet 跳转到 bigcities.jsp 页面,它利用 forEach 遍历 Map。bigcities.jsp 页面如清单 9.9 所示。
清单 9.9 bigcities.jsp 页面
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<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>
<c:forEach items="${requestScope.capitals}" var="mapItem">
<tr>
<td>${mapItem.key}</td>
<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>
<c:forEach items="${requestScope.bigCities}" var="mapItem">
<tr>
<td>${mapItem.key}</td>
<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>
最重要的是,第二个 forEach 中还嵌套了另一个 forEach:
<c:forEach items="${requestScope.bigCities}" var="mapItem">
<c:forEach items="${mapItem.value}" var="city"
varStatus="status">
${city}<c:if test="${!status.last}">,</c:if>
</c:forEach>
</c:forEach>
这里的第二个 forEach 是遍历 Map 的元素值,它是一个 String 数组。
登录以下网站可以查看到以上范例:
http://localhost:8080/iterator/bigCities
打开网页后,浏览器上应该会以 HTML 表格的形式,显示出几个国家的首都和大城市,如图 9.4 所示。
图 9.4 对 Map 使用 forEach
9.5.2 forTokens 标签
forTokens 标签用于遍历以特定分隔符隔开的令牌,其语法如下:
< c:forTokens items="stringOfTokens" delims="delimiters"
[var="varName"] [varStatus="varStatusName"]
[begin="begin"] [end="end"] [step="step"]
>
body content
< /c:forTokens>
body content 是 JSP。forTokens 标签的属性见表 9.7。
表 9.7 forTokens 标签的属性
属性 | 类型 | 描述 |
---|---|---|
var | 字符串 | 引用遍历的当前项目的有界变量名称 |
items+ | 支持的任意类型 | 要遍历的 token 字符串 |
varStatus | 字符串 | 保存遍历状态的有界变量名称。类型值为 javax.servlet.jsp.jstl. core.LoopTagStatus |
begin+ | 整数 | 遍历的起始索引,此处索引是从 0 开始的。如有指定,begin 的值必须大于或者等于 0 |
end+ | 整数 | 遍历的终止索引,此处索引是从 0 开始的 |
step+ | 整数 | 遍历将以 step 指定的间隔的 token 来处理字符串,从第一个 token 开始。如有指定,step 的值必须大于或者等于 1 |
delims+ | 字符串 | 一组分隔符 |
下面是一个 forTokens 范例:
<c:forTokens var="item" items="Argentina,Brazil,Chile" delims=",">
<c:out value="${item}"/><br/>
</c:forTokens>
当将以上 forTokens 粘贴到 JSP 中时,它将会产生如下结果:
Argentina
Brazil
Chile
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论