Chapter 30. 表达式语言增强

Seam提供了一个可扩展标准统一表达语言(EL)被称为JBoss EL。JBoss EL提供了许多增强表达和更强的EL语言方面的加强。

30.1. 参数方法绑定

标准EL默认任何参数方法都是Java代码方式。这就意味着参数方法不能被JSF方式来使用。Seam提供了一个加强式的EL允许参数包含在表达式中来表达自己。 Seam提供的 any 表达方法,包括任何JSF的绑定。例如:

<h:commandButton action="#{hotelBooking.bookHotel(hotel)}" value="Book Hotel"/>

30.1.1. 用法

参数用括号表示,用逗号分隔:

<h:commandButton action="#{hotelBooking.bookHotel(hotel, user)}" value="Book Hotel"/>

参数 hoteluser 会被作为值表达式计算,并传递到组件的 bookHotel() 方法中。这让你有了 @In 的替代方法。

任何值表达式都可以用作参数:

<h:commandButton action="#{hotelBooking.bookHotel(hotel.id, user.username)}"
                 value="Book Hotel"/>

注意: 你不能通过对象的方式来表述!所有的都要是是直接的名称,例如,hotel.iduser.username。 如果你查看下先前的代码,你将可以看到按钮命令包括这些名称。当你触发按钮事件的时候,这些名称的表述将被提交到服务器端,Seam将在action调用前来查询这些提交过来的名称(在任何一个应用程序的上下文中)。 如果这些名称表述无法在那时刻得到(因为 hoteluser 变量不能在任何应用程序的上下文中找到),action方法将返回一个 null 表述!

你甚至可以传递包含有单引号或双引号的字符串:

<h:commandLink action="#{printer.println('Hello world!')}" value="Hello"/>
<h:commandLink action="#{printer.println('Hello again')} value="Hello"/>

你可能还想把这种标记用在你所有的action方法上,不管他们是不是需要传递参数。这也能提高程序的可读性,明确表明这是方法表达式而非值表达式:

<s:link value="Cancel" action="#{hotelBooking.cancel()}"/>

30.1.2. 限制

请注意以下的限制:

30.1.2.1. 与JSP 2.1不兼容

这一扩展目前不兼容JSP 2.1。因此如果你希望将这一扩展用于JSF 1.2,你必须使用Facelets。目前这一扩展在JSP 2.0下运作正常。

30.1.2.2. 从Java代码中调用 MethodExpression

一般而言,MethodExpressionMethodBinding 被创建后,参数是通过JSF传递的。 如果是方法绑定,JSF假设不会传递参数。使用这个扩展的话,我们直到表达式被计算前,都无法知道参数类型。这就带来两个小的副作用:

  • 在Java代码中调用 MethodExpression,你传递的参数可能被忽略。定义在表达式中的参数被优先处理。

  • 通常,在任何时间调用 methodExpression.getMethodInfo().getParamTypes() 都是安全的。 但对于含有参数的表达式,你必须先调用 MethodExpression,才能调用 getParamTypes()

以上两种情况都十分罕见,而且只发生在你在Java代码中手动调用 MethodExpression 的时候。

30.2. 参数值绑定

标准EL仅允许访问属性这个成了JavaBean命名的约定。例如,表达式 #{person.name} 要求 getName() 表示当前的值。 然而许多的对象却没有恰当的命名属性或者参数。这些值能被使用的方法来调用,这个就和参数方法绑定很相似。例如,下面表达式就是使用 length() 方法返回一个字符串的大小。

#{person.name.length()}

你可以通过一个相类似的方法来访问一个集合的大小。

#{searchResults.size()}

在一般的 form #{obj.property} 表达式中可以等同于表达式 #{obj.getProperty()}。

当然参数的方式也是允许的,只要按照同样限制的方法来绑定是一样的。 下面这个例子就是通过文字字符串调用 productsByColorMethod 的。

#{controller.productsByColor('blue')}

30.3. 映射

JBoss EL支持有限的映射语法。这里要强调的一点就是这个语法不能被Facelets或者JSP解析也不能在xhtml或者JSP中使用。 我们期待在下一个JBoss EL版本中projection语法中将得到改变。

映射表达式是通过多值(list, set等等)表达式来体现一个子表达式的。例如,表达式:

#{company.departments}

可以返回一个department的list集合。如果你仅需要department name的集合,那么你的选项就要通过遍历迭代的方式来获取值。JBoss EL支持这样一个映射表达式。

#{company.departments.{d|d.name}}

子表达式被大括号{}包围起来。在这个例子中,表达式 d.name 是遍历得到的每个department值,使用 d 作为department对象的别名。 这个表达式的结果是一个String值的集合。

任何一个有效表达式的都可以在表达式中使用。假如你想知道在公司所有department(部门)个数的时候,下面它就可以很好验证书写正确性。

#{company.departments.{d|d.size()}}

映射可以被嵌套。下面的表达式返回的就是在每个department每个雇员的名字。

#{company.departments.{d|d.employees.{emp|emp.lastName}}}

嵌套映射有时可能有点棘手,下面的表达式就是返回一个所有department所有employee的集合。

#{company.departments.{d|d.employees}}

但是,它实际上要返回单个department所有employee(雇员)的集合。为了同时具有这个值,它还需要一个稍微长点的表达式。

#{company.departments.{d|d.employees.{e|e}}}