12. 表达式语言 (EL)
Web Flow 使用 EL 访问其数据模型并调用操作。 本章应让您熟悉 EL 语法、配置和您可以从流定义中引用的特殊 EL 变量。
EL 用于流程中的许多事情,包括:
-
访问客户端数据,例如声明流输入或引用请求参数。
-
访问 Web Flow 中的数据,例如 或 。
RequestContext
flowScope
currentEvent
-
通过操作调用 Spring 管理的对象上的方法。
-
解析表达式,例如状态转换条件、子流 ID 和视图名称。
EL 还用于将表单参数绑定到模型对象,反之,从模型对象的属性渲染格式化的表单字段。 但是,当将 Web Flow 与 JSF 一起使用时,这并不适用。 在这种情况下,标准 JSF 组件生命周期适用。
12.1. 表达式类型
需要理解的一个重要概念是 Web Flow 中有两种类型的表达式:
12.1.1. 标准表达式
第一种也是最常见的表达式类型是标准表达式。
此类表达式由 EL 直接计算,无需括在分隔符中,例如 .
以下示例显示了此类标准表达式:\#{}
<evaluate expression="searchCriteria.nextPage()" />
前面的表达式是一个标准表达式,它在计算时调用变量上的方法。
如果尝试将此表达式括在特殊分隔符(如 )中,则会得到一个 .
在这种情况下,分隔符被视为冗余。
该属性唯一可接受的值是单个表达式字符串。nextPage
searchCriteria
\#{}
IllegalArgumentException
expression
12.1.2. 模板表达式
第二种类型的表达式是模板表达式。
模板表达式允许将文本文本与一个或多个标准表达式混合。
每个标准表达式块都显式地用分隔符括起来。
以下示例显示了一个模板表达式:\#{}
<view-state id="error" view="error-#{externalContext.locale}.xhtml" />
上述表达式是模板表达式。
evaluation 的结果是将文本文本(如 和 )与 evaluate 的结果连接起来的字符串。
此处需要显式分隔符来划分模板中的标准表达式块。error-
.xhtml
externalContext.locale
有关接受标准表达式的 XML 属性和接受模板表达式的 XML 属性的完整列表,请参阅 Web 流 XML 架构。 您还可以在 Eclipse 中使用 F2(或其他 IDE 中的等效快捷方式)在键入特定流定义属性时访问可用文档。 |
12.2. EL 实现
Spring Web Flow 支持以下 EL(表达式语言)实现:
12.2.1. Spring EL
Web Flow 使用 Spring 表达式语言 (Spring EL)。Spring EL 的创建是为了提供一种单一的、得到充分支持的表达式语言,供 Spring 产品组合中的所有产品使用。
它在 Spring 框架中作为单独的 jar () 分发。org.springframework.expression
12.2.2. 统一 EL
使用统一 EL 还意味着对 的依赖性,尽管这通常由 Web 容器提供。
尽管 Spring EL 是默认和推荐使用的表达式语言,但您可以将其替换为 Unified EL。
为此,您需要以下 Spring 配置以插入到:el-api
WebFlowELExpressionParser
flow-builder-services
<webflow:flow-builder-services expression-parser="expressionParser"/>
<bean id="expressionParser" class="org.springframework.webflow.expression.el.WebFlowELExpressionParser">
<constructor-arg>
<bean class="org.jboss.el.ExpressionFactoryImpl" />
</constructor-arg>
</bean>
请注意,如果您的应用程序注册了自定义转换器,请务必确保 配置了具有这些自定义转换器的转换服务,如下所示:WebFlowELExpressionParser
<webflow:flow-builder-services expression-parser="expressionParser" conversion-service="conversionService"/>
<bean id="expressionParser" class="org.springframework.webflow.expression.el.WebFlowELExpressionParser">
<constructor-arg>
<bean class="org.jboss.el.ExpressionFactoryImpl" />
</constructor-arg>
<property name="conversionService" ref="conversionService"/>
</bean>
<bean id="conversionService" class="somepackage.ApplicationConversionService"/>
12.3. EL 可移植性
通常,您会发现 Spring EL 和 Unified EL 具有非常相似的语法。
但是,Spring El 有一些优势。 例如,Spring EL 与 Spring 3 的类型转换紧密集成,这使您可以充分利用其功能。 具体来说,目前只有 Spring EL 支持泛型类型的自动检测以及格式注释的使用。
从 Unified EL 升级到 Spring EL 时,请记住以下细微更改:
-
流定义中描绘的表达式必须更改为(请注意前导退格字符)。
${}
\#{}
-
测试当前事件的表达式(例如 )必须更改为(注意添加了 )。
#{currentEvent == 'submit'}
\#{currentEvent.id == 'submit'}
id
-
解析属性(如 )可能会导致 a 没有任何检查,如 .更好的选择是安全导航运算符:。
#{currentUser.name}
NullPointerException
\#{currentUser != null ? currentUser.name : null}
\#{currentUser?.name}
有关 Spring EL 语法的更多信息,请参阅 Spring 文档中的 Language Reference 部分。
12.4. 特殊 EL 变量
您可以从流程中引用多个隐式变量。
请记住以下一般规则:
仅当将新变量分配给其中一个范围时,才应使用引用数据范围 (、 、 等) 的变量。flowScope
viewScope
requestScope
例如,当将调用结果分配给名为 的新变量时,您必须为其添加 scope 变量前缀,以让 Web Flow 知道您希望将其存储在哪里。
以下示例显示了如何执行此操作:bookingService.findHotels(searchCriteria)
hotels
<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow" ... >
<var name="searchCriteria" class="org.springframework.webflow.samples.booking.SearchCriteria" />
<view-state id="reviewHotels">
<on-render>
<evaluate expression="bookingService.findHotels(searchCriteria)" result="viewScope.hotels" />
</on-render>
</view-state>
</flow>
但是,在设置现有变量时(如以下示例中),您应该直接引用该变量,而不为其添加任何范围变量前缀,如下所示:searchCriteria
<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow" ... >
<var name="searchCriteria" class="org.springframework.webflow.samples.booking.SearchCriteria" />
<view-state id="reviewHotels">
<transition on="sort">
<set name="searchCriteria.sortBy" value="requestParameters.sortBy" />
</transition>
</view-state>
</flow>
以下是您可以在流程定义中引用的隐式变量列表:
12.4.1. 变量flowScope
您可以使用 来分配流变量。
流范围在流开始时分配,在流结束时销毁。
使用默认实现,存储在 flow scope 中的任何对象都需要是可序列化的。
下面的清单定义了一个变量:flowScope
flowScope
<evaluate expression="searchService.findHotel(hotelId)" result="flowScope.hotel" />
12.4.2. 变量viewScope
您可以使用 来分配视图变量。
View 作用域在进入 a 时分配,在 state 退出时销毁。
视图范围只能从 .
使用默认实现,存储在视图范围内的任何对象都需要是可序列化的。
下面的清单定义了一个变量:viewScope
view-state
view-state
viewScope
<on-render>
<evaluate expression="searchService.findHotels(searchCriteria)" result="viewScope.hotels"
result-type="dataModel" />
</on-render>
12.4.3. 变量requestScope
可用于分配请求变量。
请求范围在调用流时分配,并在流返回时销毁。
下面的清单定义了一个变量:requestScope
requestScope
<set name="requestScope.hotelId" value="requestParameters.id" type="long" />
12.4.4. 变量flashScope
可用于分配 flash 变量。
Flash 范围在流启动时分配,在每次视图渲染后清除,并在流结束时销毁。
使用默认实现,存储在 flash scope 中的任何对象都需要是可序列化的。
下面的清单定义了一个变量:flashScope
flashScope
<set name="flashScope.statusMessage" value="'Booking confirmed'" />
12.4.5. 变量conversationScope
可用于分配对话变量。
对话范围在顶级流开始时分配,并在顶级流结束时销毁。
对话范围由顶级流及其所有子流共享。
使用默认实现,对话范围的对象存储在 HTTP 会话中,并且通常应该是可序列化的,以考虑典型的会话复制。
下面的清单定义了一个变量:conversationScope
conversationScope
<evaluate expression="searchService.findHotel(hotelId)" result="conversationScope.hotel" />
12.4.6. 变量requestParameters
该变量访问客户端请求参数,如下所示:requestParameters
<set name="requestScope.hotelId" value="requestParameters.id" type="long" />
12.4.7. 变量currentEvent
该变量访问 current 的属性,如下所示:currentEvent
Event
<evaluate expression="booking.guests.add(currentEvent.attributes.guest)" />
12.4.8. 变量currentUser
该变量访问 authenticated ,如下所示:currentUser
Principal
<evaluate expression="bookingService.createBooking(hotelId, currentUser.name)"
result="flowScope.booking" />
12.4.9. 变量messageContext
该变量访问上下文以检索和创建流执行消息,包括错误和成功消息。
有关更多信息,请参阅 Javadocs。
以下示例使用变量:messageContext
MessageContext
messageContext
<evaluate expression="bookingValidator.validate(booking, messageContext)" />
12.4.10. 变量resourceBundle
该变量访问 message 资源,如下所示:resourceBundle
<set name="flashScope.successMessage" value="resourceBundle.successMessage" />
12.4.11. 变量flowRequestContext
该变量访问 API,该 API 是当前流请求的表示形式。
有关更多信息,请参阅 API Javadocs。flowRequestContext
RequestContext
12.4.12. 变量flowExecutionContext
该变量访问 API,API 是当前流状态的表示形式。
有关更多信息,请参阅 API Javadocs。flowExecutionContext
FlowExecutionContext
12.4.14. 变量externalContext
该变量访问客户端环境,包括用户会话属性。
有关更多信息,请参阅 API JavaDocs。
以下示例使用变量:externalContext
ExternalContext
externalContext
<evaluate expression="searchService.suggestHotels(externalContext.sessionMap.userProfile)"
result="viewScope.hotels" />
12.5. 范围搜索算法
如本节前面所述,在其中一个流范围中分配变量时,需要引用该范围。 以下示例显示了如何执行此操作:
<set name="requestScope.hotelId" value="requestParameters.id" type="long" />
当您仅访问其中一个 scope 中的变量时,引用 scope 是可选的,如下所示:
<evaluate expression="entityManager.persist(booking)" />
如果未指定范围,如前面所示的 using ,则使用范围搜索算法。
该算法在 request、flash、view、flow 和 conversation 范围内查找变量。
如果未找到此类变量,则抛出 an。booking
EvaluationException