5.5 遍历行为
当需要无数次地遍历一个对象集合时,遍历行为就很有帮助。JSTL
提供了forEach
和forTokens
两个执行遍历行为的标签:这两个标签将在接下来的小节中讨论。
5.5.1 forEach标签
forEach
标签会无数次地反复遍历body content
或者对象集合。可以被遍历的对象包括java.util.Collection
和java.util.Map
的所有实现类,以及对象数组或者主类型。也可以遍历java.util.Iterator
和java.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}" /> </c:forEach>
|
step属性
1 2 3
| <c:forEach var="x" begin="1" end="10" step="2"> <c:out value="${x}" /> </c:forEach>
|
运行结果:1 3 5 7 9
遍历有界变量
下面的forEach
标签将遍历有界变量address
的phones
属性:
1 2 3
| <c:forEach var="phone" items="${address.phones}"> ${phone}"<br/> </c:forEach>
|
在本例中,有界变量命名为phone
。forEach
标签中的EL
表达式用于显示phone
的值。
获取遍历的次数
forEach
标签有一个类型为javax.servlet.jsp.jstl.core.LoopTagStatus
的变量varStatus
。LoopTagStatus
接口带有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); request.setAttribute("books", books); RequestDispatcher rd = request.getRequestDispatcher("/books.jsp"); rd.forward(request, response); } }
|
BooksServlet
的doGet
方法中创建了几本书,保存在书籍列表中,然后把书籍列表设置为请求对象的属性.最后再调用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 { 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
。要分别利用key
和value
属性引用一个Map key
和一个Map
值。遍历Map
的伪代码如下:
1 2 3
| <c:forEach var="mapItem" items="map"> ${mapItem.key} : ${mapItem.value} </c:forEach>
|
下一个范例展示了forEach
与Map
的结合使用。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<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); } }
|
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<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<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>
|
显示效果如下: