【JavaWeb学习 | 第20篇】EL表达式与JSTL标签


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

文章目录

EL 表达式与 JSTL 标签详解

在 JSP 开发中,直接嵌入 Java 小脚本会导致页面结构混乱、维护困难,而 EL 表达式与 JSTL 标签的组合,能完美解决这一问题。它们不仅让页面代码更简洁,还实现了业务逻辑与视图的分离。

一、Servlet回顾🍂

在学习新内容前,先巩固几个关键前置知识点,帮助更好理解后续内容:

  1. Servlet 是接收请求并做出响应的程序,开发方式包括实现 Servlet 接口或继承 HttpServlet,可通过注解或 XML 配置映射路径。
  2. Servlet 生命周期分为实例化、初始化(init)、处理请求(service)、销毁(destroy)四个阶段,随容器启动而创建,随容器关闭而销毁。
  3. 转发通过 RequestDispatcher 的 forward 方法实现,重定向通过 response 的 sendRedirect 方法实现,二者核心区别在于请求域数据是否共享。
  4. 过滤器可拦截请求与响应,多个过滤器组成过滤器链,开发需实现 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 使用前提

  1. 引入依赖jar包:jstl.jar 和 standard.jar
  2. 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代码块中找到对应的iffor语句,容易出错。
      • 代码冗长,增加了阅读和理解的难度。
健壮性与安全性对比
  • 使用 EL + JSTL:
    • 更健壮
      • EL表达式对null有天然的免疫力。如果zhangsannull${zhangsan.score}会返回null,在条件判断中会被当作false,不会抛出NullPointerException
      • JSTL标签(如<c:forEach>)在集合为null时通常会静默处理(不执行循环),增加了页面的稳定性。
  • 不使用 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和类型转换,易出错。
开发效率 ,减少重复编码,专注业务。 ,编写大量样板代码,效率低下。

如果我的内容对你有帮助,请 点赞 , 评论 , 收藏 。创作不易,大家的支持就是我坚持下去的动力!

相关推荐
lihao lihao1 小时前
模板进阶
java·数据结构·算法
鸿途优学-UU教育2 小时前
2025搜狐教育年度盛典|UU教育CEO彭普杰:成人学习不止于知识传递,科技赋能背后更需温度守护
科技·学习
山风wind2 小时前
Spring中责任链模式的工业级应用简单剖析
java·spring·责任链模式
后端小张2 小时前
【TextIn大模型加速器 + 火山引擎】TextIn大模型加速器与火山引擎协同构建智能文档处理新范式
人工智能·学习·数据挖掘·langchain·tensorflow·gpt-3·火山引擎
Element_南笙2 小时前
BUG:ModuleNotFoundError: No module named ‘milvus_lite‘
java·服务器·数据库
yyy(十一月限定版)2 小时前
C++基础
java·开发语言·c++
Coder_Boy_2 小时前
分布式系统设计经验总结:金融vs电商的核心差异与决策思路
java·运维·微服务·金融·电商
yuhaiqun19892 小时前
发现前端性能瓶颈的巧妙方法:建立“现象归因→分析定位→优化验证”的闭环思维
前端·经验分享·笔记·python·学习·课程设计·学习方法
d111111111d2 小时前
使用STM32 HAL库配置ADC单次转换模式详解
笔记·stm32·单片机·嵌入式硬件·学习
To Be Clean Coder2 小时前
【Spring源码】getBean源码实战(一)
java·后端·spring