
🌈 个人主页: Hygge_Code
🔥 热门专栏:从0开始学习Java | Linux学习| 计算机网络
💫 个人格言: "既然选择了远方,便不顾风雨兼程"

文章目录
- [EL 表达式与 JSTL 标签详解](#EL 表达式与 JSTL 标签详解)
-
- 一、Servlet回顾🍂
- [二、EL 表达式(简化数据访问)🥝](#二、EL 表达式(简化数据访问)🥝)
- [三、JSTL 标签(解决页面逻辑处理)🥝](#三、JSTL 标签(解决页面逻辑处理)🥝)
-
- [1. 什么是 JSTL](#1. 什么是 JSTL)
- [2. JSTL 标签库分类](#2. JSTL 标签库分类)
- [3. JSTL 使用前提](#3. JSTL 使用前提)
- [4. 核心标签库常用标签🐦🔥](#4. 核心标签库常用标签🐦🔥)
-
- (1)通用标签:set、out、remove🍋🟩
-
- [1. `<c:out>`](#1.
<c:out>) - [2. `<c:set>`](#2.
<c:set>) - [3. `<c:remove>`](#3.
<c:remove>)
- [1. `<c:out>`](#1.
- (2)语法标签:if、choose、forEach🍋🟩
-
- [1. `<c:if>`](#1.
<c:if>) - [2. `<c:choose>` / `<c:when>` / `<c:otherwise>`](#2.
<c:choose>/<c:when>/<c:otherwise>) - [3. 循环标签:`forEach`](#3. 循环标签:
forEach)
- [1. `<c:if>`](#1.
- (3)格式化标签库常用标签🍋🟩
- [四、案例:EL + JSTL 综合应用 🌰](#四、案例:EL + JSTL 综合应用 🌰)
EL 表达式与 JSTL 标签详解
在 JSP 开发中,直接嵌入 Java 小脚本会导致页面结构混乱、维护困难,而 EL 表达式与 JSTL 标签的组合,能完美解决这一问题。它们不仅让页面代码更简洁,还实现了业务逻辑与视图的分离。
一、Servlet回顾🍂
在学习新内容前,先巩固几个关键前置知识点,帮助更好理解后续内容:
- Servlet 是接收请求并做出响应的程序,开发方式包括实现 Servlet 接口或继承 HttpServlet,可通过注解或 XML 配置映射路径。
- Servlet 生命周期分为实例化、初始化(init)、处理请求(service)、销毁(destroy)四个阶段,随容器启动而创建,随容器关闭而销毁。
- 转发通过 RequestDispatcher 的 forward 方法实现,重定向通过 response 的 sendRedirect 方法实现,二者核心区别在于请求域数据是否共享。
- 过滤器可拦截请求与响应,多个过滤器组成过滤器链,开发需实现 Filter 接口或继承 HttpFilter,通过 XML 或注解配置生效。
二、EL 表达式(简化数据访问)🥝
1. 什么是 EL 表达式
EL(Expression Language)即表达式语言,是 JSP 内置的简化数据访问的语言,无需编写复杂 Java 代码即可获取域对象中的数据。
2. 为什么要用 EL 表达式
直接使用 Java 小脚本存在诸多弊端:
- 代码结构混乱,Java 代码与 HTML 标签混合交织;
- 数据取值需手动实例化对象、强制类型转换,易出错;
- 代码可读性差,后期维护成本高。
EL 表达式可替代小脚本,实现数据自动转型,让页面代码更简洁清晰。
3. EL 表达式核心用法🍋🟩
(1)获取变量值
语法:${变量名}
- 无需指定域对象时,EL 会按 pageScope → requestScope → sessionScope → applicationScope 的顺序自动查找;
- 若多个域对象存在同名变量,优先取作用范围更小的(如 request 优先于 session)。
示例:
java
// Servlet 中存入数据
request.setAttribute("username", "test");
session.setAttribute("username", "admin");
JSP 页面取值:
jsp
<!-- 输出 test(优先取 request 域数据) -->
当前用户:${username}
<!-- 指定取 session 域数据,输出 admin -->
当前管理员:${sessionScope.username}
(2)EL 隐式对象
通过隐式对象可直接指定取值范围,避免同名变量冲突,常用隐式对象如下:

(3)获取复杂数据
- JavaBean 属性 :
${对象名.属性名}或${对象名["属性名"]}
示例:${user.id}、${user["username"]} - List 集合 :
${集合名[下标]}(下标从 0 开始)
示例:${userList[0].username}(获取集合第一个用户的用户名) - Map 集合 :
${集合名.键名}或${集合名["键名"]}
示例:${scoreMap.math}、${scoreMap["english"]}
(4)EL 操作符
EL 支持关系运算、逻辑运算和空值判断,语法简洁直观:

三、JSTL 标签(解决页面逻辑处理)🥝
1. 什么是 JSTL
JSTL(JavaServer Pages Standard Tag Library)即 JSP 标准标签库,是一套基于 XML 的标签集合,弥补了 EL 无法进行逻辑判断和循环的不足,常与 EL 配合使用。
2. JSTL 标签库分类
JSTL 包含多个功能标签库,开发中最常用核心标签库和格式化标签库:
| 标签库名称 | 资源标识符(uri) | 前缀(prefix) | 核心用途 |
|---|---|---|---|
| 核心标签库 | http://java.sun.com/jsp/jstl/core | c | 逻辑判断、循环、变量操作 |
| 国际化/格式化标签库 | http://java.sun.com/jsp/jstl/fmt | fmt | 日期、数字格式化 |
| XML 标签库 | http://java.sun.com/jsp/jstl/xml | x | XML 数据处理(较少用) |
| 数据库标签库 | http://java.sun.com/jsp/jstl/sql | sql | 数据库操作(较少用) |
| 函数标签库 | http://java.sun.com/jsp/jstl/functions | fn | 字符串处理函数 |
3. JSTL 使用前提
- 引入依赖jar包:jstl.jar 和 standard.jar
- JSP 页面顶部声明标签库,示例:
jsp
<!-- 引入核心标签库 -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!-- 引入格式化标签库 -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
4. 核心标签库常用标签🐦🔥
(1)通用标签:set、out、remove🍋🟩

1. <c:out>
用于输出数据到页面,类似 <%= %>,但更安全
jsp
<c:out value="${sessionScope.username}" default="匿名用户" />
value:要输出的表达式(EL 表达式)default:当 value 为null时显示的默认值
2. <c:set>
用于在作用域(page、request、session、application)中设置变量。
jsp
<c:set var="age" value="25" scope="session" />
<c:set var="user" value="${sessionScope.userInfo}" />
var:变量名value:变量值(可直接写或用 EL 表达式)scope:作用域(默认 page)
3. <c:remove>
jsp
<c:remove var="变量名" [scope="作用域"] />
var:要移除的变量的名称
scope:指定要在哪个作用域中移除变量。如果不指定,它会依次在所有作用域(page, request, session, application)中查找该变量并移除(可选属性)
(2)语法标签:if、choose、forEach🍋🟩
1. <c:if>
条件判断标签,满足条件时执行标签体内容。
jsp
<c:if test="${user.age >= 18}">
<p>您已成年,可以访问该内容。</p>
</c:if>
test:条件表达式(返回 boolean)
2. <c:choose> / <c:when> / <c:otherwise>
多条件判断,类似 Java 的 if-else if-else。
jsp
<c:choose>
<c:when test="${user.score >= 90}">
<p>优秀</p>
</c:when>
<c:when test="${user.score >= 80}">
<p>良好</p>
</c:when>
<c:otherwise>
<p>加油</p>
</c:otherwise>
</c:choose>
3. 循环标签:forEach
遍历集合或数组,是最常用的 JSTL 标签:
jsp
<!-- 遍历 List 集合 -->
<c:forEach items="${userList}" var="user" begin="0" end="4" step="1">
用户名:${user.username}<br>
</c:forEach>
<!-- 遍历 Map 集合 -->
<c:forEach items="${scoreMap}" var="score">
科目:${score.key},分数:${score.value}<br>
</c:forEach>
items:待遍历的集合/数组;var:每次遍历的元素别名;begin:遍历起始下标(默认 0);end:遍历结束下标;step:遍历步长(默认 1)。
(3)格式化标签库常用标签🍋🟩

(1)fmt:formatDate:日期格式化
jsp
<% request.setAttribute("now", new Date()); %>
<!-- 格式:年-月-日 -->
当前日期:<fmt:formatDate value="${now}" pattern="yyyy-MM-dd" />
<!-- 格式:年-月-日 时:分:秒 -->
当前时间:<fmt:formatDate value="${now}" pattern="yyyy-MM-dd HH:mm:ss" />
运行结果:
(2)fmt:formatNumber:数字格式化
支持货币、百分比、自定义格式:
jsp
<% request.setAttribute("money", 12345.678); %>
<!-- 货币格式(自动适配 locale) -->
货币:<fmt:formatNumber value="${money}" type="currency" />
<!-- 保留 2 位小数 -->
数字:<fmt:formatNumber value="${money}" type="number" maxFractionDigits="2" />
<!-- 百分比格式 -->
百分比:<fmt:formatNumber value="${0.75}" type="percent" />
运行结果:
四、案例:EL + JSTL 综合应用 🌰
下面通过一个用户列表展示案例,看如何结合 EL 和 JSTL 开发页面:
index.jsp文件
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>首页</title>
</head>
<body>
<a href="showScore">显示成绩</a>
</body>
</html>
ScoreServlet文件
java
package com.servlet;
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.Arrays;
import java.util.List;
@WebServlet("/showScore")
public class ScoreServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.getSession().setAttribute("zhangsan",new Score("张三",90));
List<Score> scores = Arrays.asList(
new Score("林七夜",90),
new Score("江梦南",91),
new Score("微微",92),
new Score("夏至",93)
);
req.getSession().setAttribute("scores",scores);
resp.sendRedirect("score.jsp");
}
}
score.jsp文件
jsp
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--引入核心标签库--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<html>
<head>
<title>成绩信息展示</title>
</head>
<body>
<c:if test="${sessionScope.zhangsan.score > 80}" var="result" scope="request">
<div>成绩高于80</div>
</c:if>
<div>成绩高于80吗? ${requestScope.result}</div>
<c:choose>
<c:when test="${sessionScope.zhangsan.score > 90}">
<div>成绩优秀</div>
</c:when>
<c:when test="${sessionScope.zhangsan.score > 80}">
<div>成绩良好</div>
</c:when>
<c:when test="${sessionScope.zhangsan.score > 70}">
<div>成绩中等</div>
</c:when>
<c:otherwise>
<div>成绩很差</div>
</c:otherwise>
</c:choose>
<table>
<thead>
<tr>
<th>姓名</th>
<th>成绩</th>
</tr>
</thead>
<tbody>
<c:forEach items="${sessionScope.scores}" var="score">
<tr>
<td>${score.name}</td>
<td>${score.score}</td>
</tr>
</c:forEach>
</tbody>
<% request.setAttribute("now", new Date()); %>
<!-- 格式:年-月-日 -->
当前日期:<fmt:formatDate value="${now}" pattern="yyyy-MM-dd" />
<!-- 格式:年-月-日 时:分:秒 -->
当前时间:<fmt:formatDate value="${now}" pattern="yyyy-MM-dd HH:mm:ss" />
</table>
<% request.setAttribute("money", 12345.678); %>
<!-- 货币格式(自动适配 locale) -->
货币:<fmt:formatNumber value="${money}" type="currency" />
<!-- 保留 2 位小数 -->
数字:<fmt:formatNumber value="${money}" type="number" maxFractionDigits="2" />
<!-- 百分比格式 -->
百分比:<fmt:formatNumber value="${0.75}" type="percent" />
</body>
</html>
运行结果(点击链接"显示成绩"后):
对比版本:不使用EL表达式和JSTL标签🤔🤔🤔
jsp
<%@ page import="com.servlet.Score" %>
<%@ page import="java.util.List" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="java.util.Date" %>
<%@ page import="java.text.NumberFormat" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>成绩信息展示 (使用Scriptlet)</title>
</head>
<body>
<%
Score zhangsan = (Score) session.getAttribute("zhangsan");
boolean result = false;
if (zhangsan != null && zhangsan.getScore() > 80) {
result = true;
out.println("<div>成绩高于80</div>");
}
request.setAttribute("result", result);
%>
<div>成绩高于80吗? <%= request.getAttribute("result") %></div>
<%
if (zhangsan != null) {
if (zhangsan.getScore() > 90) {
%>
<div>成绩优秀</div>
<%
} else if (zhangsan.getScore() > 80) {
%>
<div>成绩良好</div>
<%
} else if (zhangsan.getScore() > 70) {
%>
<div>成绩中等</div>
<%
} else {
%>
<div>成绩很差</div>
<%
}
} else {
// 处理zhangsan为null的情况
out.println("<div>未找到用户信息</div>");
}
%>
<table>
<thead>
<tr>
<th>姓名</th>
<th>成绩</th>
</tr>
</thead>
<tbody>
<%
@SuppressWarnings("unchecked")
List<Score> scores = (List<Score>) session.getAttribute("scores");
if (scores != null && !scores.isEmpty()) {
for (Score score : scores) {
%>
<tr>
<td><%= score.getName() %></td>
<td><%= score.getScore() %></td>
</tr>
<%
}
}
%>
</tbody>
</table>
<%
Date now = new Date();
request.setAttribute("now", now);
SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat sdfDateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
%>
<!-- 格式:年-月-日 -->
当前日期:<%= sdfDate.format(now) %>
<!-- 格式:年-月-日 时:分:秒 -->
当前时间:<%= sdfDateTime.format(now) %>
<%
double money = 12345.678;
request.setAttribute("money", money);
NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance();
NumberFormat numberFormatter = NumberFormat.getNumberInstance();
numberFormatter.setMaximumFractionDigits(2);
NumberFormat percentFormatter = NumberFormat.getPercentInstance();
%>
<!-- 货币格式(自动适配 locale) -->
货币:<%= currencyFormatter.format(money) %>
<!-- 保留 2 位小数 -->
数字:<%= numberFormatter.format(money) %>
<!-- 百分比格式 -->
百分比:<%= percentFormatter.format(0.75) %>
</body>
</html>
区别分析
- EL表达式 :
- 简洁 :
${sessionScope.zhangsan.score > 80}一行代码替代了Scriptlet中获取对象、类型转换、null检查和条件判断的多行代码。 - 直观 :语法接近自然语言,
zhangsan.score直接对应zhangsan.getScore(),可读性极高。
- 简洁 :
- JSTL标签 :
- 结构化 :
<c:if>,<c:choose>,<c:forEach>等标签提供了清晰的逻辑结构,避免了Scriptlet中<% ... %>代码块与HTML标签的混乱交织。 - 专注视图:标签将Java逻辑封装起来,JSP页面更像一个专注于展示的模板。
- 结构化 :
维护成本对比
- 使用 EL + JSTL:
- 低维护成本 :
- 代码逻辑清晰,易于理解和追踪。
- 如需修改判断条件(如将
> 80改为>= 85),只需修改EL表达式中的数字,非常直观。 - 如需修改循环或格式化规则,只需调整标签的属性。
- 低维护成本 :
- 不使用 EL + JSTL:
- 高维护成本 :
- 代码逻辑分散在多个
<% ... %>块中,阅读时需要在Java代码和HTML之间频繁切换上下文。 - 修改逻辑时,需要在Java代码块中找到对应的
if或for语句,容易出错。 - 代码冗长,增加了阅读和理解的难度。
- 代码逻辑分散在多个
- 高维护成本 :
健壮性与安全性对比
- 使用 EL + JSTL:
- 更健壮 :
- EL表达式对
null有天然的免疫力。如果zhangsan为null,${zhangsan.score}会返回null,在条件判断中会被当作false,不会抛出NullPointerException。 - JSTL标签(如
<c:forEach>)在集合为null时通常会静默处理(不执行循环),增加了页面的稳定性。
- EL表达式对
- 更健壮 :
- 不使用 EL + JSTL:
- 较脆弱 :
- 必须 手动进行
null检查(if (zhangsan != null)),否则程序可能因NullPointerException而崩溃。 - 类型转换错误(如将一个
String强制转为Score)也会导致运行时异常。
- 必须 手动进行
- 较脆弱 :
开发效率对比
- 使用 EL + JSTL:
- 高开发效率 :
- 减少了大量重复的模板代码(如
getAttribute、类型转换、for循环结构)。 - 开发者可以更专注于业务逻辑和页面呈现,而非底层的Java语法细节。
- 减少了大量重复的模板代码(如
- 高开发效率 :
- 不使用 EL + JSTL:
- 低开发效率 :
- 需要编写大量模版代码,增加了编码工作量。
- 代码量大,也增加了出现语法错误的可能性。
- 低开发效率 :
对比总结
| 对比维度 | 使用 EL表达式 + JSTL标签 | 不使用 (Scriptlet) |
|---|---|---|
| 代码简洁度 | 高,代码量少,逻辑清晰。 | 低 ,代码冗长,充满<% ... %>块。 |
| 可读性 | 高,语法直观,接近自然语言,结构分明。 | 低,Java代码与HTML标签混杂,难以阅读。 |
| 维护成本 | 低,逻辑集中,修改方便,不易出错。 | 高,逻辑分散,修改时需在Java与HTML间切换。 |
| 健壮性 | 高 ,自动处理null,减少空指针异常。 |
低 ,需手动处理null和类型转换,易出错。 |
| 开发效率 | 高,减少重复编码,专注业务。 | 低,编写大量样板代码,效率低下。 |
如果我的内容对你有帮助,请 点赞 , 评论 , 收藏 。创作不易,大家的支持就是我坚持下去的动力!



