杰瑞科技汇

Java JSP中EL表达式如何使用?

目录

  1. 什么是 EL 表达式?
  2. EL 表达式的基本语法
  3. EL 中的 11 个隐含对象
  4. EL 中的运算符
  5. EL 访问数据(重点)
    • 访问 JavaBean 属性
    • 访问 List/数组元素
    • 访问 Map 键值对
    • 访问作用域变量
  6. EL 的其他重要特性
    • 空值处理
    • 启用/禁用 EL
  7. 综合示例:一个完整的 JSP + EL + JavaBean 示例

什么是 EL 表达式?

EL (Expression Language),即表达式语言,是一种轻量级的脚本语言,旨在简化 JSP 页面中数据的访问。

Java JSP中EL表达式如何使用?-图1
(图片来源网络,侵删)

在 JSP 2.0 之前,我们通常使用 JSP Scriptlet(<% ... %>)或 JSP Expression(<%= ... %>)来在页面上显示 Java 代码中的数据,这种方式存在以下问题:

  • 代码混乱:HTML 和 Java 代码混杂在一起,可读性差,难以维护。
  • 职责不清:JSP 页面本应负责显示(View),却包含了业务逻辑和数据处理,违反了 MVC 设计模式。

EL 表达式就是为了解决这些问题而生的,它提供了一种简洁、易于理解的方式来访问和显示数据,让 JSP 页面更加干净,专注于展示。

核心思想:让 JSP 回归到“视图”的角色,将复杂的逻辑处理交给 Servlet 或 JavaBean。


EL 表达式的基本语法

EL 表达式的语法非常简单,所有表达式都包含在 和 之间。

Java JSP中EL表达式如何使用?-图2
(图片来源网络,侵删)
${expression}

要显示一个名为 name 的变量,只需写:

Hello, ${name}!

这比使用 JSP Expression <%= name %> 要简洁得多。


EL 中的 11 个隐含对象

EL 提供了一系列隐含对象,可以直接在 EL 表达式中使用,无需创建,它们就像是 JSP 内置对象的“简化版”或“只读版”。

EL 隐含对象 对应 JSP 对象 描述
pageScope pageContext 访问当前页面作用域 (PageContext) 的属性
requestScope request 访问请求作用域 (HttpServletRequest) 的属性
sessionScope session 访问会话作用域 (HttpSession) 的属性
applicationScope application 访问应用作用域 (ServletContext) 的属性
param request.getParameter() 获取请求参数的单个值(字符串)
paramValues request.getParameterValues() 获取请求参数的多个值(字符串数组)
header request.getHeader() 获取请求头的单个值(字符串)
headerValues request.getHeaders() 获取请求头的多个值(枚举)
initParam application.getInitParameter() 获取 web.xml 中配置的上下文初始化参数
cookie request.getCookies() 获取客户端的 Cookie 对象
pageContext pageContext 访问 PageContext 实例本身

注意:这些对象都是只读的,你不能在 EL 中给它们赋值,${param.name = "John"} 是错误的。


EL 中的运算符

EL 提供了一套完整的运算符,可以进行算术、逻辑、关系和空值判断。

运算符类型 运算符 描述 示例
算术 , , , , div, , mod 加、减、乘、除、取模 ${price * 1.1}
${10 div 3} (等同于 )
关系 , eq, , ne, <, lt, >, gt, <=, le, >=, ge 等于、不等于、小于、大于等 ${age > 18}
${password ne '123456'}
逻辑 &&, and, \|\|, or, , not 与、或、非 ${isVip and price > 100}
空值判断 empty 判断一个对象是否为 null 或空(字符串长度为0、集合/数组大小为0) ${empty userList} (userList 为 null 或空列表,返回 true)
三元运算 A ? B : C A 为 true,返回 B,否则返回 C ${user.isVip ? 'VIP' : '普通用户'}

EL 访问数据(重点)

EL 最强大的功能之一就是能够轻松地访问存放在不同作用域中的 Java 对象及其属性。

基础规则: 和 []

  • (点号):用于访问对象的属性,要求属性名必须是合法的 Java 标识符(不能有空格、特殊字符)。
    ${user.name}  // 访问 user 对象的 getName() 方法
  • [] (方括号):用于访问对象的属性或集合/数组的元素,当属性名包含特殊字符(如 user.name)、是变量或数字时,必须使用 []
    ${user['first-name']} // 属性名包含 '-',必须用 []
    ${paramValues['hobbies'][0]} // 访问请求参数 hobbies 数组的第一个元素
    ${list[0]} // 访问 list 的第一个元素

访问 JavaBean 属性

假设在作用域中有一个 User 对象,它有 name, age 属性。

// 假设 user 对象已存入 request 作用域
// request.setAttribute("user", new User("张三", 25));
// EL 会自动从 page -> request -> session -> application 作用域中查找
// 如果同名,scope 可以指定来源
${user.name}   // 输出: 张三
${user.age}    // 输出: 25
${user['age']} // 同样有效

访问 List/数组元素

假设 requestScope 中有一个 List<String>

// List<String> skills = Arrays.asList("Java", "JSP", "EL");
// request.setAttribute("skills", skills);
${skills[0]}   // 输出: Java
${skills[1]}   // 输出: JSP
${skills[2]}   // 输出: EL

访问 Map 键值对

假设 requestScope 中有一个 Map<String, Object>

// Map<String, Object> data = new HashMap<>();
// data.put("username", "admin");
// data.put("loginTime", new Date());
// request.setAttribute("data", data);
${data.username}   // 输出: admin (通过 key 访问 value)
${data['loginTime']} // 输出: 当前日期时间对象 (会调用 toString())
${data['loginTime'].year + 1900} // 访问 Date 对象的 year 属性 (注意:year 是从1900年开始的)

作用域查找机制

当你在 EL 中写 ${user.name} 时,EL 会按照以下顺序自动查找 user 这个变量:

  1. pageScope
  2. requestScope
  3. sessionScope
  4. applicationScope

一旦在某个作用域中找到,就立即返回,不再继续查找,如果所有作用域都找不到,EL 会返回空字符串 ,而不会抛出 NullPointerException

如果你想明确指定从某个作用域获取,可以使用 scope 对象:

${requestScope.user.name} // 只从 request 作用域查找
${sessionScope.user.name} // 只从 session 作用域查找

EL 的其他重要特性

空值处理

这是 EL 的一个巨大优势,当访问一个不存在的属性或对象时,EL 会优雅地处理,而不会导致页面崩溃。

<%
    User user = null;
    request.setAttribute("user", user);
%>
// 使用 JSP Expression,会抛出 NullPointerException
// <%= ((User)request.getAttribute("user")).getName() %>
// 使用 EL,会安全地返回空字符串
${user.name} // 输出: ""
${empty user} // 输出: true

启用/禁用 EL

  • 全局禁用:在 web.xml 中配置,会禁用整个 Web 应用中的 EL。
    <jsp-config>
        <jsp-property-group>
            <url-pattern>*.jsp</url-pattern>
            <el-ignored>true</el-ignored>
        </jsp-property-group>
    </jsp-config>
  • 页面级禁用:在 JSP 页面中使用 isELIgnored 指令。
    <%@ page isELIgnored="true" %>
    <%-- 从此行开始,所有 ${...} 都会被当作普通文本输出 --%>

综合示例:一个完整的 JSP + EL + JavaBean 示例

目标:创建一个 JSP 页面,显示一个用户信息和他的订单列表。

创建 JavaBean (User.java 和 Order.java)

// User.java
package com.example;
import java.util.List;
public class User {
    private String name;
    private int age;
    private List<Order> orders;
    // 构造器、Getter/Setter 方法
    public User(String name, int age, List<Order> orders) {
        this.name = name;
        this.age = age;
        this.orders = orders;
    }
    public String getName() { return name; }
    public int getAge() { return age; }
    public List<Order> getOrders() { return orders; }
}
// Order.java
package com.example;
public class Order {
    private String orderId;
    private double amount;
    // 构造器、Getter/Setter 方法
    public Order(String orderId, double amount) {
        this.orderId = orderId;
        this.amount = amount;
    }
    public String getOrderId() { return orderId; }
    public double getAmount() { return amount; }
}

创建 Servlet (UserServlet.java) 来准备数据

// UserServlet.java
package com.example;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
@WebServlet("/user")
public class UserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 准备用户数据
        List<Order> orders = Arrays.asList(
            new Order("ORD001", 99.99),
            new Order("ORD002", 199.50)
        );
        User user = new User("李四", 30, orders);
        // 将 User 对象存入 request 作用域
        request.setAttribute("user", user);
        // 转发到 JSP 页面
        request.getRequestDispatcher("/user_info.jsp").forward(request, response);
    }
}

创建 JSP 页面 (user_info.jsp)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>用户信息</title>
</head>
<body>
    <h1>用户详情</h1>
    <hr>
    <h2>基本信息</h2>
    <p>姓名: ${user.name}</p>
    <p>年龄: ${user.age}</p>
    <p>是否成年: ${user.age > 18 ? '是' : '否'}</p>
    <hr>
    <h2>订单列表</h2>
    <c:if test="${not empty user.orders}">
        <table border="1" cellpadding="5">
            <tr>
                <th>订单ID</th>
                <th>订单金额</th>
            </tr>
            <c:forEach items="${user.orders}" var="order">
                <tr>
                    <td>${order.orderId}</td>
                    <td>¥${order.amount}</td>
                </tr>
            </c:forEach>
        </table>
    </c:if>
    <c:if test="${empty user.orders}">
        <p>该用户暂无订单。</p>
    </c:if>
</body>
</html>

注意:上面的 JSP 用到了 JSTL (JSP Standard Tag Library) 的 <c:if><c:forEach> 标签,在实际开发中,EL 和 JSTL 是黄金搭档,EL 负责提供数据,JSTL 负责逻辑控制和循环。

访问流程

  1. 用户访问 http://localhost:8080/your-app/user
  2. UserServlet 被调用,创建 User 对象并存入 request 作用域。
  3. Servlet 将请求转发到 user_info.jsp
  4. user_info.jsp 页面被解析,EL 表达式 ${user.name}request 作用域中找到 user 对象,并调用其 getName() 方法获取值 "李四",然后显示在页面上。
  5. 同理,${user.orders} 获取订单列表,<c:forEach> 标签遍历这个列表,并用 EL 显示每个订单的 orderIdamount

特性 描述
简洁性 语法 极其简洁,替代了繁琐的 <%=%><%...%>
可读性 代码清晰,HTML 和数据访问逻辑分离,页面更易维护。
自动查找 自动在四个作用域中查找变量,简化了开发。
安全性 优雅地处理空值,避免 NullPointerException
只读性 专注于数据展示,符合 MVC 思想,防止在视图中修改数据。
运算能力 内置丰富的运算符,可以在页面进行简单的逻辑判断和计算。

最佳实践: 在现代 JSP 开发中,应优先使用 EL 表达式来显示数据,并结合 JSTL 标签来处理流程控制、循环等逻辑,尽量避免在 JSP 页面中使用 Scriptlet,以保持代码的整洁和可维护性。

分享:
扫描分享到社交APP
上一篇
下一篇