Contents

JSF EL 简介

1. 简介

表达式语言 (EL) 是一种脚本语言,已在许多 Java 框架中采用,例如带有SpEL 的 Spring和带有 JBoss EL 的 JBoss。

在本文中,我们将重点介绍 JSF 对这种脚本语言的实现 - Unified EL。

EL 目前处于 3.0 版,这是一个重大升级,允许处理引擎在独立模式下使用——例如,在 Java SE 平台上。以前的版本依赖于符合 Jakarta EE 的应用程序服务器或 Web 容器。本文讨论 EL 版本 2.2。

2. 即时和延期评估

JSF 中 EL 的主要功能是连接 JSF 视图(通常是 XHTML 标记)和基于 java 的后端。后端可以是用户创建的托管 bean,也可以是容器托管的对象,例如 HTTP 会话。

我们将关注 EL 2.2。JSF 中的 EL 有两种通用形式,即立即语法 EL 和延迟语法 EL。

2.1. 立即语法 EL

也称为 JSP EL,这是一种脚本格式,是 Java Web 应用程序开发的 JSP 时代的遗留物。

JSP EL 表达式以美元符号 ( $ ) 开头,然后是左大括号 ( { ),然后是实际表达式,最后以右大括号 ( } ) 结束:

${ELBean.value > 0}

这个语法:

  1. 在页面的生命周期中仅评估一次(在开始时)。这意味着它的价值。上例中的被表达式读取必须在页面加载之前设置。
  2. 提供对 bean 值的只读访问。
  3. 因此,需要遵守 JavaBean 命名约定。

对于大多数用途,这种形式的 EL 不是很通用。

2.2. 延迟执行 EL

延迟执行 EL 是专为 JSF 设计的 EL。它与 JSP EL 的主要语法区别在于它用“ *#”*而不是“ $ ”标记。

#{ELBean.value > 0}

延迟EL:

  1. 与 JSF 生命周期同步。这意味着延迟 EL 中的 EL 表达式在 JSF 页面呈现的不同点(开始和结束)进行评估。
  2. 提供对 bean 值的读写访问。这允许使用 EL 在 JSF backing-bean(或其他任何地方)中设置一个值。
  3. 允许程序员在对象上调用任意方法,并根据 EL 的版本,将参数传递给这些方法。

统一EL 是统一延迟 EL 和 JSP EL 的规范,允许在同一页面中使用两种语法。

3. 统一EL

统一EL 允许两种通用的表达式,值表达式和方法表达式。

还有一个简短的说明——以下部分将显示一些示例,这些示例都可以在应用程序中找到,导航到:

http://localhost:8080/jsf/el_intro.jsf

3.1. 值表达式

值表达式允许我们读取或设置托管 bean 属性,具体取决于它的放置位置。

以下表达式将托管 bean 属性读取到页面上:

Hello, #{ELBean.firstName}

然而,下面的表达式允许我们在用户对象上设置一个值:

<h:inputText id="firstName" value="#{ELBean.firstName}" required="true"/>

变量必须遵循 JavaBean 命名约定才有资格进行这种处理。对于要提交的 bean 的值,只需要保存封闭形式。

3.2. 方法表达式

Unified EL 提供方法表达式来从 JSF 页面中执行公共的、非静态的方法。这些方法可能有也可能没有返回值。

这是一个简单的例子:

<h:commandButton value="Save" action="#{ELBean.save}"/>

所引用的save()方法是在名为ELBean 的支持 bean 上定义的。

从 EL 2.2 开始,您还可以将参数传递给使用 EL 访问的方法。这可以让我们重写我们的例子:

<h:inputText id="firstName" binding="#{firstName}" required="true"/>
<h:commandButton value="Save"
  action="#{ELBean.saveFirstName(firstName.value.toString().concat('(passed)'))}"/>

我们在这里所做的是为inputText组件创建一个页面范围的绑定表达式,并将value属性直接传递给方法表达式。

请注意,该变量在没有任何特殊符号、花括号或转义字符的情况下传递给方法。

3.3. 隐式 EL 对象

JSF EL 引擎提供对多个容器管理对象的访问。他们之中有一些是:

  • #{Application}:也可用作*#{servletContext}*,这是表示 Web 应用程序实例的对象
  • #{applicationScope}:可在 Web 应用程序范围内访问的变量映射
  • #{Cookie}:HTTP Cookie 变量的映射
  • #{facesContext}FacesContext的当前实例
  • #{flash}:JSF Flash 范围对象
  • #{header}:当前请求中 HTTP 标头的映射
  • #{initParam}:Web 应用程序的上下文初始化变量的映射
  • #{param}:HTTP 请求查询参数的映射
  • #{request}HTTPServletRequest对象
  • #{requestScope}:请求范围的变量映射
  • #{sessionScope}:一个会话范围的变量映射
  • #{session}HTTPSession对象
  • #{viewScope}:视图(页面)范围的变量映射

以下简单示例通过访问headers隐式对象列出所有请求标头和值:

<c:forEach items="#{header}" var="header">
   <tr>
       <td>#{header.key}</td>
       <td>#{header.value}</td>
   </tr>
</c:forEach>

4. 你可以在 EL 中做什么

EL 具有多功能性,可以在 Java 代码、XHTML 标记、Javascript 甚至 JSF 配置文件(如faces-config.xml文件)中使用。让我们检查一些具体的用例。

4.1. 在页面标记中使用 EL

EL 可以出现在标准 HTML 标签中:

<meta name="description" content="#{ELBean.pageDescription}"/>

4.2. 在 JavaScript 中使用 EL

在 Javascript 或 <script> 标签中遇到 EL 时会被解释:

<script type="text/javascript"> var theVar = #{ELBean.firstName};</script>

支持 bean 变量将在此处设置为 javascript 变量。

4.3. 使用运算符评估 EL 中的布尔逻辑

EL 支持相当高级的比较运算符:

  • eq等式运算符,相当于“ ==”。
  • lt小于运算符,相当于“<”。
  • le小于或等于运算符,相当于“<=”。
  • gt大于运算符,相当于“>”。
  • ge大于等于,等价于“ >=“。

4.4. 在 Backing Bean 中评估 EL

在支持 bean 代码中,可以使用 JSF 应用程序评估 EL 表达式。这开辟了一个可能性的世界,将 JSF 页面与支持 bean 连接起来。您可以检索隐式 EL 对象,或从支持 bean 轻松检索实际的 HTML 页面组件或其值:

FacesContext ctx = FacesContext.getCurrentInstance(); 
Application app = ctx.getApplication(); 
String firstName = app.evaluateExpressionGet(ctx, "#{firstName.value}", String.class); 
HtmlInputText firstNameTextBox = app.evaluateExpressionGet(ctx, "#{firstName}", HtmlInputText.class);

这使开发人员在与 JSF 页面交互时具有很大的灵活性。

5. 在 EL 中你不能做什么

EL < 3.0 确实有一些限制。以下部分讨论其中的一些。

5.1. 不重载

EL 不支持使用重载。因此,在具有以下方法的支持 bean 中:

public void save(User theUser);
public void save(String username);
public void save(Integer uid);

JSF EL 将无法正确评估以下表达式

<h:commandButton value="Save" action="#{ELBean.save(firstName.value)}"/>

JSF ELResolver将自省bean的类定义,并选择java.lang.Class#getMethods返回的第一个方法(返回类中可用方法的方法)。返回的方法的顺序无法保证,这将不可避免地导致未定义的行为。

5.2. 没有枚举或常量值

JSF EL < 3.0,不支持在脚本中使用常量值或枚举。因此,具有以下任何一项

public static final String USER_ERROR_MESS = "No, you can’t do that";
enum Days { Sat, Sun, Mon, Tue, Wed, Thu, Fri };

表示您将无法执行以下操作

<h:outputText id="message" value="#{ELBean.USER_ERROR_MESS}"/>
<h:commandButton id="saveButton" value="save" rendered="bean.offDay==Days.Sun"/>

5.3. 没有内置的空安全

JSF EL < v3.0 不提供隐式 null 安全访问,有些人可能会觉得现代脚本引擎很奇怪。

因此,如果以下表达式中的person为 null,则整个表达式将失败,并带有难看的 NPE

Hello Mr, #{ELBean.person.surname}"