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

个人主页: Hygge_Code
个人格言: “既然选择了远方,便不顾风雨兼程”

在这里插入图片描述

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)。

示例:

// Servlet 中存入数据
request.setAttribute("username", "test");
session.setAttribute("username", "admin");

JSP 页面取值:


当前用户:${username}

当前管理员:${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/corec逻辑判断、循环、变量操作
国际化/格式化标签库http://java.sun.com/jsp/jstl/fmtfmt日期、数字格式化
XML 标签库http://java.sun.com/jsp/jstl/xmlxXML 数据处理(较少用)
数据库标签库http://java.sun.com/jsp/jstl/sqlsql数据库操作(较少用)
函数标签库http://java.sun.com/jsp/jstl/functionsfn字符串处理函数

3. JSTL 使用前提

  1. 引入依赖jar包:jstl.jar 和 standard.jar
  2. 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>

用于输出数据到页面,类似 <%= %>,但更安全

  • value:要输出的表达式(EL 表达式)
  • default:当 value 为 null 时显示的默认值

2. <c:set>

用于在作用域(page、request、session、application)中设置变量。


  • var:变量名
  • value:变量值(可直接写或用 EL 表达式)
  • scope:作用域(默认 page)
3. <c:remove>

var:要移除的变量的名称
scope:指定要在哪个作用域中移除变量。如果不指定,它会依次在所有作用域(page, request, session, application)中查找该变量并移除(可选属性)

(2)语法标签:if、choose、forEach‍
1. <c:if>

条件判断标签,满足条件时执行标签体内容。


    

您已成年,可以访问该内容。

  • test:条件表达式(返回 boolean)

2. <c:choose> / <c:when> / <c:otherwise>

多条件判断,类似 Java 的 if-else if-else


    
        

优秀

良好

加油


3. 循环标签:forEach

遍历集合或数组,是最常用的 JSTL 标签:



  用户名:${user.username}
科目:${score.key},分数:${score.value}
  • items:待遍历的集合/数组;
  • var:每次遍历的元素别名;
  • begin:遍历起始下标(默认 0);
  • end:遍历结束下标;
  • step:遍历步长(默认 1)。
(3)格式化标签库常用标签‍

在这里插入图片描述

(1)fmt:formatDate:日期格式化
<% request.setAttribute("now", new Date()); %>

当前日期:

当前时间:

运行结果:

在这里插入图片描述

(2)fmt:formatNumber:数字格式化

支持货币、百分比、自定义格式:

<% request.setAttribute("money", 12345.678); %>

货币:

数字:

百分比:

运行结果:

在这里插入图片描述


四、案例:EL + JSTL 综合应用

下面通过一个用户列表展示案例,看如何结合 EL 和 JSTL 开发页面:

index.jsp文件

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

  
    首页
  
  
  显示成绩
  

ScoreServlet文件

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文件

<%@ 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"%>


    成绩信息展示


    
        
成绩高于80
成绩高于80吗? ${requestScope.result}
成绩优秀
成绩良好
成绩中等
成绩很差
<% request.setAttribute("now", new Date()); %> 当前日期: 当前时间:
姓名 成绩
${score.name} ${score.score}
<% request.setAttribute("money", 12345.678); %> 货币: 数字: 百分比:

运行结果(点击链接"显示成绩"后):

在这里插入图片描述

对比版本:不使用EL表达式和JSTL标签

<%@ 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" %>


    成绩信息展示 (使用Scriptlet)


<%
    Score zhangsan = (Score) session.getAttribute("zhangsan");
    boolean result = false;
    if (zhangsan != null && zhangsan.getScore() > 80) {
        result = true;
        out.println("
成绩高于80
"); } request.setAttribute("result", result); %>
成绩高于80吗? <%= request.getAttribute("result") %>
<% if (zhangsan != null) { if (zhangsan.getScore() > 90) { %>
成绩优秀
<% } else if (zhangsan.getScore() > 80) { %>
成绩良好
<% } else if (zhangsan.getScore() > 70) { %>
成绩中等
<% } else { %>
成绩很差
<% } } else { // 处理zhangsan为null的情况 out.println("
未找到用户信息
"); } %> <% @SuppressWarnings("unchecked") List scores = (List) session.getAttribute("scores"); if (scores != null && !scores.isEmpty()) { for (Score score : scores) { %> <% } } %>
姓名 成绩
<%= score.getName() %> <%= score.getScore() %>
<% 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(); %> 货币:<%= currencyFormatter.format(money) %> 数字:<%= numberFormatter.format(money) %> 百分比:<%= percentFormatter.format(0.75) %>
区别分析
  • 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和类型转换,易出错。
开发效率,减少重复编码,专注业务。,编写大量样板代码,效率低下。

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

posted @ 2026-02-02 19:50  yangykaifa  阅读(0)  评论(0)    收藏  举报