18. 系统设置

本章向您展示如何在任何Web环境中设置Web Flow系统以供使用。spring-doc.cadn.net.cn

18.1. Java 配置和 XML 命名空间

Web Flow 提供了对基于 Java 和 XML 的配置的专用配置支持。spring-doc.cadn.net.cn

要开始使用基于 XML 的配置,请按如下方式声明 webflow 配置 XML 命名空间:spring-doc.cadn.net.cn

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:webflow="http://www.springframework.org/schema/webflow-config"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           https://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/webflow-config
           https://www.springframework.org/schema/webflow-config/spring-webflow-config.xsd">

    <!-- Setup Web Flow here -->

</beans>

要开始使用 Java 配置,请在 @Configuration 类中扩展 AbstractFlowConfiguration,如下所示:spring-doc.cadn.net.cn

import org.springframework.context.annotation.Configuration;
import org.springframework.webflow.config.AbstractFlowConfiguration;

@Configuration
public class WebFlowConfig extends AbstractFlowConfiguration {

}

18.2. 基本系统配置

接下来的两部分展示了在您的应用程序中设置 Web Flow 系统所需的最低配置:spring-doc.cadn.net.cn

18.2.1. 注册一个FlowRegistry

您可以在XML中的FlowRegistry注册您的流程,如下所示:spring-doc.cadn.net.cn

<webflow:flow-registry id="flowRegistry">
    <webflow:flow-location path="/WEB-INF/flows/booking/booking.xml" />
</webflow:flow-registry>

你可以通过以下方式在 Java 中的 FlowRegistry 注册你的流程:spring-doc.cadn.net.cn

@Bean
public FlowDefinitionRegistry flowRegistry() {
    return getFlowDefinitionRegistryBuilder()
        .addFlowLocation("/WEB-INF/flows/booking/booking.xml")
        .build();
}

18.2.2. 部署一个 FlowExecutor

你可以按照以下方式部署一个FlowExecutor,它是用于在XML中执行流的核心服务:spring-doc.cadn.net.cn

<webflow:flow-executor id="flowExecutor" />

您可以部署一个FlowExecutor,这是用于在 Java 中执行流的核心服务:spring-doc.cadn.net.cn

@Bean
public FlowExecutor flowExecutor() {
    return getFlowExecutorBuilder(flowRegistry()).build();
}

查看本指南的Spring MVC 集成JSF 集成部分,了解如何分别将 Web Flow 系统与 MVC 和 JSF 环境集成。spring-doc.cadn.net.cn

18.3. flow-registry选项

本节探讨 flow-registry 的配置选项。spring-doc.cadn.net.cn

18.3.1. 指定流程位置

您可以使用 location 元素来指定要注册的流程定义的路径。 默认情况下,除非定义了注册表基本路径(请参阅 流程位置基本路径),否则流程的注册表标识符等于其文件名减去文件扩展名。spring-doc.cadn.net.cn

以下示例指定了 XML 中的流位置:spring-doc.cadn.net.cn

<webflow:flow-location path="/WEB-INF/flows/booking/booking.xml" />

以下示例指定了 Java 中的流程位置:spring-doc.cadn.net.cn

return getFlowDefinitionRegistryBuilder()
        .addFlowLocation("/WEB-INF/flows/booking/booking.xml")
        .build();

18.3.2. 分配自定义流程标识符

您可以指定一个ID,为流程分配自定义的注册表标识符。spring-doc.cadn.net.cn

以下示例展示了如何在 XML 中分配自定义流程标识符:spring-doc.cadn.net.cn

<webflow:flow-location path="/WEB-INF/flows/booking/booking.xml" id="bookHotel" />

以下示例展示了如何在 Java 中分配自定义流程标识符:spring-doc.cadn.net.cn

return getFlowDefinitionRegistryBuilder()
        .addFlowLocation("/WEB-INF/flows/booking/booking.xml", "bookHotel")
        .build();

18.3.3. 分配流元属性

您可以使用 flow-definition-attributes 元素为已注册的流分配自定义元属性。spring-doc.cadn.net.cn

以下示例展示了如何在 XML 中分配流元属性:spring-doc.cadn.net.cn

<webflow:flow-location path="/WEB-INF/flows/booking/booking.xml">
    <webflow:flow-definition-attributes>
        <webflow:attribute name="caption" value="Books a hotel" />
    </webflow:flow-definition-attributes>
</webflow:flow-location>

以下示例展示了如何在 Java 中分配流元属性:spring-doc.cadn.net.cn

Map<String, Object> attrs = ... ;

return getFlowDefinitionRegistryBuilder()
        .addFlowLocation("/WEB-INF/flows/booking/booking.xml", null, attrs)
        .build();

18.3.4. 使用位置模式注册流程

您可以使用 flow-location-patterns 元素注册与特定资源位置模式匹配的流。spring-doc.cadn.net.cn

以下示例展示了如何在 XML 中注册一个流程:spring-doc.cadn.net.cn

<webflow:flow-location-pattern value="/WEB-INF/flows/**/*-flow.xml" />

以下示例展示了如何在 Java 中注册一个流程:spring-doc.cadn.net.cn

return getFlowDefinitionRegistryBuilder()
        .addFlowLocationPattern("/WEB-INF/flows...
        .build();

18.3.5. 流程位置基础路径

您可以使用 base-path 属性为应用程序中的所有流定义一个基础位置。 所有流的位置都相对于该基础路径。 基础路径可以是资源路径(例如 /WEB-INF)或类路径上的位置(例如 classpath:org/springframework/webflow/samples)。spring-doc.cadn.net.cn

以下示例显示了如何在 XML 中设置基础路径:spring-doc.cadn.net.cn

<webflow:flow-registry id="flowRegistry" base-path="/WEB-INF">
    <webflow:flow-location path="/hotels/booking/booking.xml" />
</webflow:flow-registry>

以下示例展示了如何在 Java 中设置基础路径:spring-doc.cadn.net.cn

return getFlowDefinitionRegistryBuilder()
        .setBasePath("/WEB-INF")
        .addFlowLocationPattern("/hotels/booking/booking.xml")
        .build();

定义基础路径后,分配流标识符的算法会略有变化。 流现在被分配的注册表标识符等于它们的基础路径和文件名之间的路径段。 例如,如果某个流定义位于 /WEB-INF/hotels/booking/booking-flow.xml,而基础路径是 /WEB-INF,那么到该流的剩余路径为 hotels/booking,这将成为流 ID。spring-doc.cadn.net.cn

为每个流程定义创建一个目录
将每个流程定义打包到一个唯一的目录中是一种最佳实践。 这样做可以提高模块化程度,让依赖的资源能够与流程定义一起打包。 当使用约定时,还可以防止两个流程拥有相同的标识符。

如果没有指定基础路径,或者流程定义直接位于基础路径上,则会使用从文件名(去掉扩展名)派生的流程ID。 例如,如果一个流程定义文件是booking.xml,那么流程标识符就简单地是bookingspring-doc.cadn.net.cn

位置模式在与注册表基础路径结合使用时特别强大。 而不是让流程标识符成为 *-flow,而是基于目录路径。 以下示例展示了如何在 XML 中将基础路径与流程位置模式结合起来:spring-doc.cadn.net.cn

<webflow:flow-registry id="flowRegistry" base-path="/WEB-INF">
    <webflow:flow-location-pattern value="/**/*-flow.xml" />
</webflow:flow-registry>

以下示例展示了如何在 Java 中将基础路径与流位置模式结合使用:spring-doc.cadn.net.cn

return getFlowDefinitionRegistryBuilder()
        .setBasePath("/WEB-INF")
        .addFlowLocationPattern("...
        .build();

在前面的示例中,假设您在WEB-INF目录内的/user/login/user/registration/hotels/booking/flights/booking目录中存在流。 那么最终会得到流ID分别为user/loginuser/registrationhotels/bookingflights/bookingspring-doc.cadn.net.cn

18.3.6. 配置 FlowRegistry 层次结构

您可以使用 parent 属性将两个流注册表通过层次结构链接在一起。 当查询子注册表时,如果找不到请求的流,它会委托给其父注册表。spring-doc.cadn.net.cn

以下示例在 XML 中为两个流注册表建立了父子关系:spring-doc.cadn.net.cn

<!-- my-system-config.xml -->
<webflow:flow-registry id="flowRegistry" parent="sharedFlowRegistry">
    <webflow:flow-location path="/WEB-INF/flows/booking/booking.xml" />
</webflow:flow-registry>

<!-- shared-config.xml -->
<webflow:flow-registry id="sharedFlowRegistry">
    <!-- Global flows shared by several applications -->
</webflow:flow-registry>

以下示例为 Java 中的两个流注册表建立了父级关系:spring-doc.cadn.net.cn

@Configuration
public class WebFlowConfig extends AbstractFlowConfiguration {

    @Autowired
    private SharedConfig sharedConfig;

    @Bean
    public FlowDefinitionRegistry flowRegistry() {
        return getFlowDefinitionRegistryBuilder()
                .setParent(this.sharedConfig.sharedFlowRegistry())
                .addFlowLocation("/WEB-INF/flows/booking/booking.xml")
                .build();
    }
}

@Configuration
public class SharedConfig extends AbstractFlowConfiguration {

    @Bean
    public FlowDefinitionRegistry sharedFlowRegistry() {
        return getFlowDefinitionRegistryBuilder()
                .addFlowLocation("/WEB-INF/flows/shared.xml")
                .build();
    }
}

18.3.7. 配置自定义FlowBuilder服务

您可以使用flow-builder-services属性(在XML中)或FlowBuilderServices对象(在Java中)来自定义用于在flow-registry中构建流程的服务和设置。 如果未指定flow-builder-services元素,则使用默认的服务实现。 当指定了该元素时,您只需引用想要自定义的服务即可。spring-doc.cadn.net.cn

以下示例显示了如何在 XML 中创建自定义流程构建器服务:spring-doc.cadn.net.cn

<webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices">
    <webflow:flow-location path="/WEB-INF/flows/booking/booking.xml" />
</webflow:flow-registry>

<webflow:flow-builder-services id="flowBuilderServices" />

以下示例展示了如何在 Java 中创建自定义的流程构建器服务:spring-doc.cadn.net.cn

@Bean
public FlowDefinitionRegistry flowRegistry() {
	return getFlowDefinitionRegistryBuilder(flowBuilderServices())
            .addFlowLocation("/WEB-INF/flows/booking/booking.xml")
            .build();
}

@Bean
public FlowBuilderServices flowBuilderServices() {
    return getFlowBuilderServicesBuilder().build();
}

可配置的服务包括conversion-serviceexpression-parserview-factory-creator元素(在XML中)以及ConversionServiceExpressionParserViewFactoryCreator接口(在Java中)。这些服务通过引用您必须定义的自定义bean来进行配置。spring-doc.cadn.net.cn

以下示例展示了如何在 XML 中定义可配置的服务:spring-doc.cadn.net.cn

<webflow:flow-builder-services id="flowBuilderServices"
    conversion-service="conversionService"
    expression-parser="expressionParser"
    view-factory-creator="viewFactoryCreator" />

<bean id="conversionService" class="..." />
<bean id="expressionParser" class="..." />
<bean id="viewFactoryCreator" class="..." />

以下示例展示了如何在 Java 中定义可配置的服务:spring-doc.cadn.net.cn

@Bean
public FlowBuilderServices flowBuilderServices() {
    return getFlowBuilderServicesBuilder()
            .setConversionService(conversionService())
            .setExpressionParser(expressionParser)
            .setViewFactoryCreator(mvcViewFactoryCreator())
            .build();
}

@Bean
public ConversionService conversionService() {
    // ...
}

@Bean
public ExpressionParser expressionParser() {
    // ...
}

@Bean
public ViewFactoryCreator viewFactoryCreator() {
    // ...
}
使用转换服务

您可以使用 conversion-service 属性(在 XML 中)或 ConversionService 接口(在 Java 中)来自定义 Web Flow 系统使用的 ConversionService。 类型转换在流执行期间需要时用于将一种类型转换为另一种类型,例如处理请求参数、调用操作等。 许多常见的对象类型(如数字、类和枚举)都受支持。 但是,您可能需要为自定义数据类型提供自己的类型转换和格式化逻辑。 请参阅 执行类型转换 以获取有关如何提供自定义类型转换逻辑的重要信息。spring-doc.cadn.net.cn

使用表达式解析器

您可以使用expression-parser属性(在XML中)或ExpressionParser接口(在Java中)来自定义Web Flow系统使用的ExpressionParser。 默认的ExpressionParser会在类路径中可用的情况下使用统一表达式语言(Unified Expression Language)。 否则,它将使用Spring表达式语言。spring-doc.cadn.net.cn

使用视图工厂创建器

你可以使用view-factory-creator属性(在XML中)或ViewFactoryCreator接口(在Java中)来自定义Web Flow系统使用的ViewFactoryCreator。 默认的ViewFactoryCreator生成能够渲染JSP、Velocity和Freemarker视图的Spring MVC视图工厂。spring-doc.cadn.net.cn

可配置的设置为 development。 这些设置是全局配置属性,您可以在流程构建过程中应用它们。spring-doc.cadn.net.cn

启用开发模式

当您创建一个流构建器服务对象时,可以开启开发模式。 开发模式会启用流定义更改的热重载,包括对依赖的流资源(如消息包)的更改。spring-doc.cadn.net.cn

要以 XML 方式开启开发模式,请将 development 属性设置在 flow-builder-services 元素上,值为 true。 要以 Java 方式开启开发模式,请对 FlowBuilderServices 对象使用 setDevelopment(true)spring-doc.cadn.net.cn

18.4. 设置流执行器选项

本节探讨流执行器的配置选项。spring-doc.cadn.net.cn

18.4.1. 附加流执行监听器

您可以使用 flow-execution-listeners 元素(在 XML 中)或 addFlowExecutionListener 方法(在 Java 中)来注册监听器,以观察流执行的生命周期。spring-doc.cadn.net.cn

以下示例展示了如何在 XML 中创建流执行监听器:spring-doc.cadn.net.cn

<webflow:flow-execution-listeners>
    <webflow:listener ref="securityListener"/>
    <webflow:listener ref="persistenceListener"/>
</webflow:flow-execution-listeners>

以下示例展示了如何在 Java 中创建流执行监听器:spring-doc.cadn.net.cn

@Bean
public FlowExecutor flowExecutor() {
    return getFlowExecutorBuilder(flowRegistry())
            .addFlowExecutionListener(securityListener())
            .addFlowExecutionListener(persistenceListener())
            .build();
}

您还可以配置一个监听器来仅观察特定的流程。spring-doc.cadn.net.cn

以下示例展示了如何在 XML 中配置监听器以仅监控两个流程:spring-doc.cadn.net.cn

<webflow:listener ref="securityListener" criteria="securedFlow1,securedFlow2"/>

以下示例展示了如何在 Java 中配置监听器以仅监控两个流:spring-doc.cadn.net.cn

@Bean
public FlowExecutor flowExecutor() {
    return getFlowExecutorBuilder(flowRegistry())
            .addFlowExecutionListener(securityListener(), "securedFlow1,securedFlow2")
            .build();
}

18.4.2. 调整流执行持久化

您可以使用 flow-execution-repository 元素(在 XML 中)或 FlowExecutor 接口(在 Java 中)来调整流执行持久化设置。spring-doc.cadn.net.cn

以下示例展示了如何在 XML 中调整流执行:spring-doc.cadn.net.cn

<webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
    <webflow:flow-execution-repository max-executions="5" max-execution-snapshots="30" />
</webflow:flow-executor>

以下示例调整了 Java 中的流执行:spring-doc.cadn.net.cn

@Bean
public FlowExecutor flowExecutor() {
    return getFlowExecutorBuilder(flowRegistry())
            .setMaxFlowExecutions(5)
            .setMaxFlowExecutionSnapshots(30)
            .build();
}
调优max-executions

您可以调整max-executions属性(在XML中),以限制每个用户会话可以创建的流执行的最大数量。 当超过最大执行数量时,最旧的执行将被移除。spring-doc.cadn.net.cn

max-executions 属性是基于用户会话的。 也就是说,它在任何流程定义的实例之间都有效。
调优max-execution-snapshots

您可以调整 max-execution-snapshots 属性来限制每次流执行可以拍摄的历史快照数量。 要禁用快照拍摄,将此值设置为 0。 要启用无限数量的快照,将此值设置为 -1。spring-doc.cadn.net.cn

历史快照启用浏览器后退按钮支持。 当快照功能被禁用时,按下浏览器的后退按钮将无法正常工作。 这样做会导致使用一个指向未记录快照的执行键。