12. 表达式语言 (EL)

Web Flow 使用 EL 访问其数据模型并调用操作。 本章应让您熟悉 EL 语法、配置和您可以从流定义中引用的特殊 EL 变量。spring-doc.cn

EL 用于流程中的许多事情,包括:spring-doc.cn

  • 访问客户端数据,例如声明流输入或引用请求参数。spring-doc.cn

  • 访问 Web Flow 中的数据,例如 或 。RequestContextflowScopecurrentEventspring-doc.cn

  • 通过操作调用 Spring 管理的对象上的方法。spring-doc.cn

  • 解析表达式,例如状态转换条件、子流 ID 和视图名称。spring-doc.cn

EL 还用于将表单参数绑定到模型对象,反之,从模型对象的属性渲染格式化的表单字段。 但是,当将 Web Flow 与 JSF 一起使用时,这并不适用。 在这种情况下,标准 JSF 组件生命周期适用。spring-doc.cn

12.1. 表达式类型

需要理解的一个重要概念是 Web Flow 中有两种类型的表达式:spring-doc.cn

12.1.1. 标准表达式

第一种也是最常见的表达式类型是标准表达式。 此类表达式由 EL 直接计算,无需括在分隔符中,例如 . 以下示例显示了此类标准表达式:\#{}spring-doc.cn

<evaluate expression="searchCriteria.nextPage()" />

前面的表达式是一个标准表达式,它在计算时调用变量上的方法。 如果尝试将此表达式括在特殊分隔符(如 )中,则会得到一个 . 在这种情况下,分隔符被视为冗余。 该属性唯一可接受的值是单个表达式字符串。nextPagesearchCriteria\#{}IllegalArgumentExceptionexpressionspring-doc.cn

12.1.2. 模板表达式

第二种类型的表达式是模板表达式。 模板表达式允许将文本文本与一个或多个标准表达式混合。 每个标准表达式块都显式地用分隔符括起来。 以下示例显示了一个模板表达式:\#{}spring-doc.cn

<view-state id="error" view="error-#{externalContext.locale}.xhtml" />

上述表达式是模板表达式。 evaluation 的结果是将文本文本(如 和 )与 evaluate 的结果连接起来的字符串。 此处需要显式分隔符来划分模板中的标准表达式块。error-.xhtmlexternalContext.localespring-doc.cn

有关接受标准表达式的 XML 属性和接受模板表达式的 XML 属性的完整列表,请参阅 Web 流 XML 架构。 您还可以在 Eclipse 中使用 F2(或其他 IDE 中的等效快捷方式)在键入特定流定义属性时访问可用文档。

12.2. EL 实现

Spring Web Flow 支持以下 EL(表达式语言)实现:spring-doc.cn

12.2.1. Spring EL

Web Flow 使用 Spring 表达式语言 (Spring EL)。Spring EL 的创建是为了提供一种单一的、得到充分支持的表达式语言,供 Spring 产品组合中的所有产品使用。 它在 Spring 框架中作为单独的 jar () 分发。org.springframework.expressionspring-doc.cn

12.2.2. 统一 EL

使用统一 EL 还意味着对 的依赖性,尽管这通常由 Web 容器提供。 尽管 Spring EL 是默认和推荐使用的表达式语言,但您可以将其替换为 Unified EL。 为此,您需要以下 Spring 配置以插入到:el-apiWebFlowELExpressionParserflow-builder-servicesspring-doc.cn

<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>

请注意,如果您的应用程序注册了自定义转换器,请务必确保 配置了具有这些自定义转换器的转换服务,如下所示:WebFlowELExpressionParserspring-doc.cn

<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-doc.cn

但是,Spring El 有一些优势。 例如,Spring EL 与 Spring 3 的类型转换紧密集成,这使您可以充分利用其功能。 具体来说,目前只有 Spring EL 支持泛型类型的自动检测以及格式注释的使用。spring-doc.cn

从 Unified EL 升级到 Spring EL 时,请记住以下细微更改:spring-doc.cn

  • 流定义中描绘的表达式必须更改为(请注意前导退格字符)。${}\#{}spring-doc.cn

  • 测试当前事件的表达式(例如 )必须更改为(注意添加了 )。#{currentEvent == 'submit'}\#{currentEvent.id == 'submit'}idspring-doc.cn

  • 解析属性(如 )可能会导致 a 没有任何检查,如 .更好的选择是安全导航运算符:。#{currentUser.name}NullPointerException\#{currentUser != null ? currentUser.name : null}\#{currentUser?.name}spring-doc.cn

有关 Spring EL 语法的更多信息,请参阅 Spring 文档中的 Language Reference 部分。spring-doc.cn

12.4. 特殊 EL 变量

您可以从流程中引用多个隐式变量。spring-doc.cn

请记住以下一般规则: 仅当将新变量分配给其中一个范围时,才应使用引用数据范围 (、 、 等) 的变量。flowScopeviewScoperequestScopespring-doc.cn

例如,当将调用结果分配给名为 的新变量时,您必须为其添加 scope 变量前缀,以让 Web Flow 知道您希望将其存储在哪里。 以下示例显示了如何执行此操作:bookingService.findHotels(searchCriteria)hotelsspring-doc.cn

<?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>

但是,在设置现有变量时(如以下示例中),您应该直接引用该变量,而不为其添加任何范围变量前缀,如下所示:searchCriteriaspring-doc.cn

<?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>

以下是您可以在流程定义中引用的隐式变量列表:spring-doc.cn

12.4.1. 变量flowScope

您可以使用 来分配流变量。 流范围在流开始时分配,在流结束时销毁。 使用默认实现,存储在 flow scope 中的任何对象都需要是可序列化的。 下面的清单定义了一个变量:flowScopeflowScopespring-doc.cn

<evaluate expression="searchService.findHotel(hotelId)" result="flowScope.hotel" />

12.4.2. 变量viewScope

您可以使用 来分配视图变量。 View 作用域在进入 a 时分配,在 state 退出时销毁。 视图范围只能从 . 使用默认实现,存储在视图范围内的任何对象都需要是可序列化的。 下面的清单定义了一个变量:viewScopeview-stateview-stateviewScopespring-doc.cn

<on-render>
    <evaluate expression="searchService.findHotels(searchCriteria)" result="viewScope.hotels"
              result-type="dataModel" />
</on-render>

12.4.3. 变量requestScope

可用于分配请求变量。 请求范围在调用流时分配,并在流返回时销毁。 下面的清单定义了一个变量:requestScoperequestScopespring-doc.cn

<set name="requestScope.hotelId" value="requestParameters.id" type="long" />

12.4.4. 变量flashScope

可用于分配 flash 变量。 Flash 范围在流启动时分配,在每次视图渲染后清除,并在流结束时销毁。 使用默认实现,存储在 flash scope 中的任何对象都需要是可序列化的。 下面的清单定义了一个变量:flashScopeflashScopespring-doc.cn

<set name="flashScope.statusMessage" value="'Booking confirmed'" />

12.4.5. 变量conversationScope

可用于分配对话变量。 对话范围在顶级流开始时分配,并在顶级流结束时销毁。 对话范围由顶级流及其所有子流共享。 使用默认实现,对话范围的对象存储在 HTTP 会话中,并且通常应该是可序列化的,以考虑典型的会话复制。 下面的清单定义了一个变量:conversationScopeconversationScopespring-doc.cn

<evaluate expression="searchService.findHotel(hotelId)" result="conversationScope.hotel" />

12.4.6. 变量requestParameters

该变量访问客户端请求参数,如下所示:requestParametersspring-doc.cn

<set name="requestScope.hotelId" value="requestParameters.id" type="long" />

12.4.7. 变量currentEvent

该变量访问 current 的属性,如下所示:currentEventEventspring-doc.cn

<evaluate expression="booking.guests.add(currentEvent.attributes.guest)" />

12.4.8. 变量currentUser

该变量访问 authenticated ,如下所示:currentUserPrincipalspring-doc.cn

<evaluate expression="bookingService.createBooking(hotelId, currentUser.name)"
          result="flowScope.booking" />

12.4.9. 变量messageContext

该变量访问上下文以检索和创建流执行消息,包括错误和成功消息。 有关更多信息,请参阅 Javadocs。 以下示例使用变量:messageContextMessageContextmessageContextspring-doc.cn

<evaluate expression="bookingValidator.validate(booking, messageContext)" />

12.4.10. 变量resourceBundle

该变量访问 message 资源,如下所示:resourceBundlespring-doc.cn

<set name="flashScope.successMessage" value="resourceBundle.successMessage" />

12.4.11. 变量flowRequestContext

该变量访问 API,该 API 是当前流请求的表示形式。 有关更多信息,请参阅 API JavadocsflowRequestContextRequestContextspring-doc.cn

12.4.12. 变量flowExecutionContext

该变量访问 API,API 是当前流状态的表示形式。 有关更多信息,请参阅 API JavadocsflowExecutionContextFlowExecutionContextspring-doc.cn

12.4.13. 变量flowExecutionUrl

该变量访问当前流程执行视图状态的上下文相对 URI。flowExecutionUrlspring-doc.cn

12.4.14. 变量externalContext

该变量访问客户端环境,包括用户会话属性。 有关更多信息,请参阅 API JavaDocs。 以下示例使用变量:externalContextExternalContextexternalContextspring-doc.cn

<evaluate expression="searchService.suggestHotels(externalContext.sessionMap.userProfile)"
          result="viewScope.hotels" />

12.5. 范围搜索算法

如本节前面所述,在其中一个流范围中分配变量时,需要引用该范围。 以下示例显示了如何执行此操作:spring-doc.cn

<set name="requestScope.hotelId" value="requestParameters.id" type="long" />

当您仅访问其中一个 scope 中的变量时,引用 scope 是可选的,如下所示:spring-doc.cn

<evaluate expression="entityManager.persist(booking)" />

如果未指定范围,如前面所示的 using ,则使用范围搜索算法。 该算法在 request、flash、view、flow 和 conversation 范围内查找变量。 如果未找到此类变量,则抛出 an。bookingEvaluationExceptionspring-doc.cn