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,通过访问varStatusindex属性获取元素索引:theLoop.index

重新访问URL,可以看到包含索引的新列:

带varStatus.index的电影列表

⚠️ 注意: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>
...

重新部署后查看结果:

带varStatus.index和varStatus.count的电影列表

表格中包含了从1开始的索引列。

4. varStatus的其他有用属性

除了indexcountvarStatus还提供其他实用属性。有时我们需要检测当前元素是否是第一个或最后一个(例如在表格中设置不同背景色)。

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>标签中通过检查varStatusfirstlast属性设置对应类名。浏览器中查看效果:

首末行高亮的电影列表

现在第一行有浅绿色背景,最后一行有橙色背景。

5. 总结

本文探讨了如何在JSP的JSTL <c:forEach>循环中访问索引值。无论是需要从0开始的索引用于逻辑处理,还是从1开始的计数用于显示,JSTL都提供了简单有效的解决方案。

此外,我们还演示了如何使用varStatusfirstlast属性检测循环中的第一次和最后一次迭代,这在需要特殊处理首末元素的场景中特别实用。


原始标题:Get the Index Values From forEach Loop in JSTL | Baeldung