我们将从最基础的方式讲起,逐步深入到更现代、更推荐的最佳实践。

核心思想
整个流程可以概括为以下几个步骤:
-
后端处理 (Java/Spring MVC):
- 在 Controller (控制器) 中,从数据库、服务层或其他地方获取一个
List对象。 - 将这个
List对象存入Model(模型) 中。 - 将请求转发到 (forward) 一个 JSP 视图页面。
- 在 Controller (控制器) 中,从数据库、服务层或其他地方获取一个
-
前端展示 (JSP):
- 在 JSP 页面中,使用 JSTL (JSP Standard Tag Library) 或 EL (Expression Language, 表达式语言) 从
Model中取出List对象。 - 使用 JSTL 的核心标签库(如
<c:forEach>)遍历List中的每一个元素。 - 在遍历过程中,将每个元素的数据(如对象的属性)动态地显示在 HTML 标签中。
- 在 JSP 页面中,使用 JSTL (JSP Standard Tag Library) 或 EL (Expression Language, 表达式语言) 从
传统 JSP + JSTL + EL (最基础、最经典的方式)
这种方式不依赖任何特定的 Web 框架,是理解 JSP 工作原理的基础。

准备工作:引入 JSTL 库
如果你使用 Maven,在 pom.xml 中添加依赖:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
后端代码 (Servlet)
假设我们有一个 User 实体类和一个 UserServlet。
User.java (POJO - Plain Old Java Object)
public class User {
private int id;
private String name;
private int age;
// 构造方法、Getter 和 Setter
public User() {}
public User(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
UserServlet.java (控制器)
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 java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@WebServlet("/userList")
public class UserServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 模拟从数据库获取数据
List<User> userList = new ArrayList<>();
userList.add(new User(1, "张三", 25));
userList.add(new User(2, "李四", 30));
userList.add(new User(3, "王五", 28));
// 2. 将 List 存入 request 域中
request.setAttribute("userList", userList);
// 3. 转发到 JSP 页面进行展示
request.getRequestDispatcher("/WEB-INF/views/userList.jsp").forward(request, response);
}
}
前端代码 (JSP)
userList.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%-- 引入 JSTL 核心标签库 --%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>用户列表</title>
<style>
table { border-collapse: collapse; width: 50%; }
th, td { border: 1px solid #dddddd; text-align: left; padding: 8px; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<h1>用户列表</h1>
<table>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>年龄</th>
</tr>
</thead>
<tbody>
<%--
c:forEach: JSTL 的核心循环标签
items: 要迭代的集合,这里是从 request 域中取出的 userList
var: 迭代过程中当前元素的临时变量名
--%>
<c:forEach items="${userList}" var="user">
<tr>
<%--
EL 表达式: ${...} 用于获取变量或对象的属性
user.id 会自动调用 user.getId() 方法
--%>
<td>${user.id}</td>
<td>${user.name}</td>
<td>${user.age}</td>
</tr>
</c:forEach>
</tbody>
</table>
</body>
</html>
访问流程:
- 在浏览器访问
http://your-domain/your-app/userList。 UserServlet的doGet方法被调用。- 创建
userList并存入request。 - 请求被转发到
userList.jsp。 - JSP 引擎解析页面,
${userList}从request中取出List<User>。 <c:forEach>开始迭代,每次迭代将一个User对象赋给变量user。- EL 表达式
${user.id}等取出user对象的属性并显示。 - 最终渲染成完整的 HTML 页面发送给浏览器。
现代方式 (Spring MVC + Thymeleaf)
在现代 Java Web 开发中,Spring Boot 是主流,它推荐使用 Thymeleaf 作为模板引擎,而不是传统的 JSP,Thymeleaf 语法更强大、更直观,并且天然支持开箱即用的热重载。
后端代码 (Spring MVC Controller)
UserController.java
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.ArrayList;
import java.util.List;
@Controller
public class UserController {
@GetMapping("/users")
public String listUsers(Model model) {
// 1. 模拟从数据库获取数据
List<User> userList = new ArrayList<>();
userList.add(new User(1, "张三", 25));
userList.add(new User(2, "李四", 30));
userList.add(new User(3, "王五", 28));
// 2. 将 List 添加到 Model 中
// Thymeleaf 会自动从 Model 中获取数据
model.addAttribute("userList", userList);
// 3. 返回视图名称 (Thymeleaf 会自动解析为 /templates/users.html)
return "users";
}
}
Model对象的作用和request.setAttribute类似,但更简洁。- 返回的字符串
"users"是视图的逻辑名称,框架会根据配置(如prefix: /templates/,suffix: .html)找到对应的模板文件。
前端代码 (Thymeleaf 模板)
src/main/resources/templates/users.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>用户列表 - Thymeleaf</title>
<style>
/* 同上 */
table { border-collapse: collapse; width: 50%; }
th, td { border: 1px solid #dddddd; text-align: left; padding: 8px; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<h1>用户列表</h1>
<table>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>年龄</th>
</tr>
</thead>
<tbody>
<!--
th:each: Thymeleaf 的迭代属性
userList: 从 Model 中取出的集合
user: 迭代变量,代表当前元素
-->
<tr th:each="user : ${userList}">
<!--
th:text: 设置元素的文本内容
${...} 是 Thymeleaf 的标准表达式语法
-->
<td th:text="${user.id}">ID</td>
<td th:text="${user.name}">Name</td>
<td th:text="${user.age}">Age</td>
</tr>
</tbody>
</table>
</body>
</html>
Thymeleaf 的优势:
- 语法更清晰:
th:each="user : ${userList}"比<c:forEach items="..." var="...">更像原生代码。 - 可读性高: 即使不启动后端服务,直接打开 HTML 文件也能看到大致布局(
ID,Name,Age这些静态文本会显示)。 - 功能强大: 提供了丰富的属性,如
th:if,th:unless,th:switch,th:href,th:src等,可以处理各种复杂的页面逻辑。
总结与对比
| 特性 | JSP + JSTL + EL | Thymeleaf (Spring Boot) |
|---|---|---|
| 技术栈 | Java EE 原生技术 | Spring 生态,现代模板引擎 |
| 依赖 | 需要 JSTL 库 | 通常由 Spring Boot 自动引入 |
| 语法 | JSTL 标签 + EL 表达式 | 专注于 HTML 标签的 th:* 属性 |
| 可读性 | 混合了 JSP 标签和 HTML,可读性一般 | 纯 HTML + 属性,静态页面可读性高 |
| 开发体验 | 需要部署到服务器才能看到效果 | 支持热重载,修改后刷新浏览器即可 |
| 推荐场景 | 维护老旧项目;学习 JSP 基础 | 所有新项目,尤其是基于 Spring Boot 的项目 |
| 性能 | 较低,编译为 Servlet | 较高,专门为高性能优化 |
如何选择?
- 如果你在学习或维护一个传统的 Java Web 项目:你必须掌握 JSP + JSTL + EL 的方式,它是理解 MVC 模式中视图层渲染的基础。
- 如果你正在开发一个新的项目,特别是使用 Spring Boot:强烈推荐使用 Thymeleaf,它更现代、更高效、开发体验更好,是当前社区的主流选择。
