EL 表达式

344 阅读3分钟

1. 产生背景

声明一个用于存储用户信息的 JavaBean

public class User {
    private String id; // 用户id
    private Bank bank; // 银行信息
    
    // 省略 get set
}

public class Bank {
    private String name;   // 银行名称
    private String number; // 银行卡号
}

我们可以使用 JSP 标准动作获取用户的 id

<jsp:getProperty name="user" property="id"/>

但如果我们想要获取用户的银行卡号时,JSP 标准动作中没有提供这种嵌套式访问机制,所以要想实现这个功能,就只能在 JSP 页面中通过 Java 代码来获取。

在 MVC 设计模式中,JSP 只是视图,视图的任务就是显示响应,而不是在 JSP 中做任何关于程序控制和业务逻辑的事情。所以在 JSP 页面中应该尽可能少的、或者是完全不出现 Java 代码。

在 JSP 2.0 之后,可以使用 EL (Expression Language) 表达式来处理这样的的问题。EL 表达式提供了在 JSP 中简化表达式的方法,目的是为了尽量减少 JSP 页面中的 Java 代码,使得 JSP 页面的处理程序编写起来更加简洁,便于开发和维护。

2. 组成部分

2.1 EL 表达式语法

  • ${ expression }

expression 指定要输出的内容,可以是字符串EL 运算符组成的表达式

2.2 EL 运算符

上面的语法中讲到 EL 运算符,接下来我们来看一下有哪些运算符,这样大家对于 ${ expression } 的中 expression 可以写哪些内容心里有个底,后面的内容我们会对这些运算符进行运用,并对注意点逐个进行验证!

2.2.1 算术运算符

算术运算符说明
+
-
*
/ 或 div
% 或 mod取余

+ 在 EL 表达式中只作为算术运算符,而不能当作字符串连接符

2.2.2 关系运算符

关系运算符说明
== 或 eq等于
!= 或 ne不等于
< 或 lt小于
> 或 gt大于
<= 或 le大于等于
>= 或 ge小于等于

2.2.3 逻辑运算符

逻辑运算符说明
&& 或 and与运算
|| 或 or或运算
! 或 not非运算

2.2.4 条件运算符

条件运算符说明
? :? 前面的条件表达式为 true 时,执行 : 前面表达式,否则执行 : 后面的表达式

2.2.5 取值运算符

取值运算符说明
.访问对象中的属性
[]访问对象中的属性
访问数组或集合
动态获取变量的值

当属性名包含 -., 等特殊符号时,只能使用 [] 运算符

2.2.6 验证运算符

验证运算符说明
empty以下几种情况返回 true
null
长度为零的 String
无元素的集合或数组

2.3 从四大域中访问数据

四大域指的就是 pageContext、request、session、application,当我们没有使用 2.4 节中的内置对象时,都是从四大域中访问数据

  • ${ varName } 的执行流程

2.3.1 访问基本数据类型

<%
    pageContext.setAttribute("id", 1);
    request.setAttribute("age", 18);
    session.setAttribute("name", "zhangfei");
    application.setAttribute("weight", 75.5);
%>

${ id } <br>
${ age } <br>
${ name } <br>
${ weight } <br>

执行结果

当不同域中存在相同的属性 name,就会按照上面的流程获取

<%
    pageContext.setAttribute("name", "pageContext");
    request.setAttribute("name", "request");
    session.setAttribute("name", "session");
    application.setAttribute("name", "application");
%>

${ name }

访问到的是 pageContext 域中的值

接下来我们注释掉 pageContext

<%
//  pageContext.setAttribute("name", "pageContext");
    request.setAttribute("name", "request");
    session.setAttribute("name", "session");
    application.setAttribute("name", "application");
%>

${ name }

执行结果

当我们注释掉 request 时,访问到的是 session,当注释掉 session 之后,访问到 application,那全部都注释掉,会是什么结果呢?

<%
//    pageContext.setAttribute("name", "pageContext");
//    request.setAttribute("name", "request");
//    session.setAttribute("name", "session");
//    application.setAttribute("name", "application");
%>

我们可以发现,使用 EL 表达式访问四大域中的数据时,会依次从 pageContext、request、session、application 中获取数据,获取不到时不展示。

那有没有办法从指定域中获取数据呢?有的,2.4.2 节我们会介绍。

接下来我们来使用一下算术运算符,关系运算符、逻辑运算符使用方法类似,就不做演示了

<%
    request.setAttribute("name", "zhangfei");
%>

${ name + 1 }

会出现 java.lang.NumberFormatException,验证了我们之前所说的 + 在 EL 表达式中只作为算术运算符,而不能当作字符串连接符

使用整型属性进行算术运算

<%
    request.setAttribute("age", 18);
%>

${ age + 1 }

结果正确

接下来使用一下条件表达式

<%
    request.setAttribute("name", "zhangfei");
%>

${ name.equals("zhangfei") ? "yes" : "no" }

2.3.2 访问对象

新建 User 类

public class User {
    private int age;
    private String name;
    
    // 省略 get set
}

这里有个注意点,User 类不能放在默认包(src)下,不然会出现 Classes from the default package must not be referenced from JSP file

我们可以使用取值运算符 . [] 获取对象中的属性

<%
    User user = new User(18, "zhangfei");
    session.setAttribute("user", user);
%>

${ user.name } <br>
${ user.["name"] } <br>

还可以使用 [] 动态获取变量的值

<%
    request.setAttribute("var", "name");
%>

${ user[var] }

由于 Java 的标识符不能包含 -., 等特殊符号,介绍取值运算符时讲到的注意事项等到使用 Map 集合时再验证!

2.3.3 访问数组或集合

我们可以使用取值运算符 [] 访问数组或集合

<%
    List<String> list = new ArrayList<>();
    list.add("C");
    list.add("Java");
    list.add("C++");
    request.setAttribute("list", list);

    String[] array = new String[]{"C", "Java", "C++"};
    session.setAttribute("array", array);
%>

${ list[0] } <br>
${ array[1] } <br>

执行结果

接下来我们使用一下验证运算符

<%
    request.setAttribute("object", null);
    request.setAttribute("str1", "");
    request.setAttribute("str2", "value");
    request.setAttribute("arr1", new String[]{});
    request.setAttribute("arr2", new String[]{"element"});
    request.setAttribute("list1", new ArrayList<>());
    request.setAttribute("list2", Collections.singleton("element"));
%>

${ empty object } <br>
${ empty str1 } <br>
${ empty str2 } <br>
${ empty arr1 } <br>
${ empty arr2 } <br>
${ empty list1 } <br>
${ empty list2 } <br>

访问 Map 集合

<%
    Map<String, String> map = new HashMap<>();
    map.put("o.name", "zhangfei");

    request.setAttribute("map", map);
%>

${ map.o.name }

获取不到值,这时因为属性名中存在特殊字符 .,这时需要使用 [] 运算符访问数据

<%
    Map<String, String> map = new HashMap<>();
    map.put("o.name", "zhangfei");

    request.setAttribute("map", map);
%>

${ map["o.name"] }

2.4 从内置对象中访问数据

内置对象可以分为六类,分别是:

  • JSP
  • 作用域
  • 请求参数
  • 请求头
  • Cookie
  • 初始化参数

除了 pageContext 内置对象,其他内置对象本质上是一个 Map 类

2.4.1 JSP

  • pageContext

(1)本质

javax.servlet.jsp.PageContext

(2)使用

比较常见的用法是获取项目路径

${ pageContext.request.contextPath }

2.4.2 作用域

  • pageScope
  • requestScopre
  • sessionScope
  • applicationScope

(1)本质

pageContext.getAttribute(var);
request.getAttribute(var);
session.getAttribute(var);
application.getAttribute(var);

(2)使用

还是使用上面的例子,但是这次我们从指定域中获取数据

<%
    pageContext.setAttribute("name", "pageContext");
    request.setAttribute("name", "request");
    session.setAttribute("name", "session");
    application.setAttribute("name", "application");
%>

${ pageScope.name } <br>
${ requestScope.name } <br>
${ sessionScope.name } <br>
${ applicationScope.name } <br>

2.4.3 请求参数

  • param
  • paramValues

(1)本质

request.getParameter(var);
request.getParameterValues(var);

(2)使用

param.html

<form action="param.jsp" method="POST">
    姓名:<input type="text" name="userName"> <br>
    爱好:<input type="checkbox" name="hobby" value="C">C
    <input type="checkbox" name="hobby" value="Java">Java
    <input type="checkbox" name="hobby" value="C++">C++ <br>
    <input type="submit" value="提交">
</form>

param.jsp

${ param.userName } <br>
${ paramValues.hobby[0] } <br>

运行结果

2.4.4 请求头

  • header
  • headerValues

(1)本质

request.getHeader(var);
request.getHeaders(var);

(2)使用

${ header.Host } <br>
${ headerValues.Cookie[0] }

2.4.5 Cookie

  • cookie

(1)本质

Cookie[] cookies = request.getCookies();
Map<String, Cookie> map = new HashMap<>();
for (Cookie cookie : cookies) {
    map.put(cookie.getName(), cookie);
}

(2)使用

${ cookie.JSESSIONID.name } <br>
${ cookie.JSESSIONID.value } <br>

2.4.6 initParam

  • initParam

(1)本质

servletContext.getInitParameter(var)

(2)使用

在 web.xml 中配置初始化参数

<web-app>
    <context-param>
        <param-name>key1</param-name>
        <param-value>value1</param-value>
    </context-param>

    <context-param>
        <param-name>key2</param-name>
        <param-value>value2</param-value>
    </context-param>
</web-app>

initParam.jsp

${ initParam.key1 } <br>
${ initParam.key2 } <br>