1. 概述
在开发JavaServer Pages(JSP)时,我们经常使用JavaServer Pages标准标签库(JSTL)来简化代码。其中最常用的标签之一是<c:forEach>
,它允许我们遍历数组、列表或Map等集合。在遍历过程中,我们经常需要访问每个元素的索引。
本教程将探讨如何在使用JSTL的<c:forEach>
标签遍历时获取元素的索引值。
2. 创建简单示例
我们将创建一个简单的Spring-MVC JSTL Web应用来展示预定义的电影列表。为简化起见,我们跳过Spring配置(如ViewResolver)。
首先看Movie
这个POJO类:
public class Movie {
private String title;
private int year;
public Movie(String title, int year) {
this.title = title;
this.year = year;
}
//... getter和setter方法已省略
}
然后需要一个Spring控制器类处理HTTP请求:
@Controller
public class JSTLForEachDemoController {
@RequestMapping(value = "/foreach-demo", method = RequestMethod.GET)
public ModelAndView forEachDemo(final Model model) {
ModelAndView mv = new ModelAndView("jstlForEachDemo");
List<Movie> movies = List.of(
new Movie("拆弹部队", 2008),
new Movie("美丽心灵", 2001),
new Movie("沉默的羔羊", 1991),
new Movie("日月精忠", 1966),
new Movie("老无所依", 2007)
);
mv.addObject("movieList", movies);
return mv;
}
}
这个控制器只有一个方法处理/foreach-demo
的GET请求。我们创建了一个硬编码的Movie
对象列表,并将其添加到名为movieList
的ModelAndView对象中。视图定义为jstlForEachDemo
。
最后创建JSP视图文件webapp/WEB-INF/views/jstlForEachDemo.jsp
:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<style>
table, th, td {
border: 1px solid black;
border-collapse: collapse;
}
</style>
<head>
<title>JSTL ForEach示例</title>
</head>
<body>
<h1>电影列表</h1>
<div>
<table style="width: 50%">
<tr>
<th>年份</th>
<th>标题</th>
</tr>
<c:forEach var="movie" items="${movieList}">
<tr>
<td>${movie.year}</td>
<td>${movie.title}</td>
</tr>
</c:forEach>
</table>
</div>
</body>
</html>
我们使用JSTL的<c:forEach>
标签遍历movieList
对象,生成HTML表格行。部署到Tomcat等Servlet容器后,访问URL可以看到电影数据:
接下来我们看看如何在forEach遍历中获取每个Movie元素的索引。
3. 使用varStatus访问索引和计数
JSTL提供了内置机制获取forEach循环中的元素索引。varStatus
属性允许我们定义一个循环状态变量,提供关于迭代的元数据。
修改<c:forEach>
标签,添加varStatus
属性并在表格中显示元素索引:
...
<h1>电影列表</h1>
<div>
<table style="width: 50%">
<tr>
<th>varStatus.index</th>
<th>年份</th>
<th>标题</th>
</tr>
<c:forEach var="movie" items="${movieList}" varStatus="theLoop">
<tr>
<td>${theLoop.index}</td>
<td>${movie.year}</td>
<td>${movie.title}</td>
</tr>
</c:forEach>
</table>
</div>
...
我们将varStatus
命名为theLoop
,通过访问varStatus
的index
属性获取元素索引:theLoop.index
。
重新访问URL,可以看到包含索引的新列:
⚠️ 注意:varStatus.index
是从0开始的。如果需要从1开始的索引,可以使用varStatus.count
属性:
...
<h1>电影列表</h1>
<div>
<table style="width: 50%">
<tr>
<th>varStatus.index</th>
<th>varStatus.count</th>
<th>年份</th>
<th>标题</th>
</tr>
<c:forEach var="movie" items="${movieList}" varStatus="theLoop">
<tr>
<td>${theLoop.index}</td>
<td>${theLoop.count}</td>
<td>${movie.year}</td>
<td>${movie.title}</td>
</tr>
</c:forEach>
</table>
</div>
...
重新部署后查看结果:
表格中包含了从1开始的索引列。
4. varStatus的其他有用属性
除了index
和count
,varStatus
还提供其他实用属性。有时我们需要检测当前元素是否是第一个或最后一个(例如在表格中设置不同背景色)。
varStatus
提供了两个布尔属性:
- ✅
first
:检测是否是第一次迭代 - ✅
last
:检测是否是最后一次迭代
修改代码,为第一行和最后一行设置不同背景色:
...
<style>
...
.first { background-color: lightgreen }
.last { background-color: orange }
</style>
...
<h1>电影列表</h1>
<div>
<table style="width: 50%">
<tr>
<th>varStatus.index</th>
<th>varStatus.count</th>
<th>年份</th>
<th>标题</th>
</tr>
<c:forEach var="movie" items="${movieList}" varStatus="theLoop">
<tr ${ theLoop.first ? 'class="first"' : '' } ${ theLoop.last ? 'class="last"' : '' }>
<td>${theLoop.index}</td>
<td>${theLoop.count}</td>
<td>${movie.year}</td>
<td>${movie.title}</td>
</tr>
</c:forEach>
</table>
</div>
...
我们定义了两个CSS类,在<tr>
标签中通过检查varStatus
的first
和last
属性设置对应类名。浏览器中查看效果:
现在第一行有浅绿色背景,最后一行有橙色背景。
5. 总结
本文探讨了如何在JSP的JSTL <c:forEach>
循环中访问索引值。无论是需要从0开始的索引用于逻辑处理,还是从1开始的计数用于显示,JSTL都提供了简单有效的解决方案。
此外,我们还演示了如何使用varStatus
的first
和last
属性检测循环中的第一次和最后一次迭代,这在需要特殊处理首末元素的场景中特别实用。