18. System Setup

This chapter shows you how to set up the Web Flow system for use in any web environment.spring-doc.cn

18.1. Java Configuration and the XML Namespace

Web Flow provides dedicated configuration support for both Java- and XML-based configuration.spring-doc.cn

To get started with XML based configuration, declare the webflow config XML namespace, as follows:spring-doc.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>

To get started with Java configuration extend AbstractFlowConfiguration in an @Configuration class, as follows:spring-doc.cn

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

@Configuration
public class WebFlowConfig extends AbstractFlowConfiguration {

}

18.2. Basic System Configuration

The next two sections show the minimal configuration required to set up the Web Flow system in your application:spring-doc.cn

18.2.1. Registering a FlowRegistry

You can register your flows in a FlowRegistry in XML, as follows:spring-doc.cn

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

You can register your flows in a FlowRegistry in Java, as follows:spring-doc.cn

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

18.2.2. Deploying a FlowExecutor

You can deploy a FlowExecutor, the central service for executing flows in XML, as follows:spring-doc.cn

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

You can deploy a FlowExecutor, the central service for executing flows in Java:spring-doc.cn

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

See the Spring MVC Integration and JSF Integration sections of this guide on how to integrate the Web Flow system with the MVC and JSF environment, respectively.spring-doc.cn

18.3. flow-registry options

This section explores flow-registry configuration options.spring-doc.cn

18.3.1. Specifying Flow Locations

You can use the location element to specify paths to flow definitions that you want to register. By default, flows are assigned registry identifiers equal to their filenames minus the file extension, unless a registry base path is defined (see Flow Location Base Path).spring-doc.cn

The following example specifies a flow location in XML:spring-doc.cn

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

The following example specifies a flow location in Java:spring-doc.cn

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

18.3.2. Assigning Custom Flow Identifiers

You can specify an ID to assign a custom registry identifier to a flow.spring-doc.cn

The following example shows how to assign custom flow identifiers in XML:spring-doc.cn

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

The following example shows how to assign custom flow identifiers in Java:spring-doc.cn

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

18.3.3. Assigning Flow Meta-attributes

You can use the flow-definition-attributes element to assign custom meta-attributes to a registered flow.spring-doc.cn

The following example shows how to assign flow meta-attributes in XML:spring-doc.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>

The following example shows how to assign flow meta-attributes in Java:spring-doc.cn

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

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

18.3.4. Registering Flows by Using a Location Pattern

You can use the flow-location-patterns element to register flows that match a specific resource location pattern.spring-doc.cn

The following example shows how to register a flow in XML:spring-doc.cn

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

The following example shows how to register a flow in Java:spring-doc.cn

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

18.3.5. Flow Location Base Path

You can use the base-path attribute to define a base location for all flows in the application. All flow locations are then relative to the base path. The base path can be a resource path (such as /WEB-INF) or a location on the classpath (such as classpath:org/springframework/webflow/samples).spring-doc.cn

The following example shows how to set the base path in XML:spring-doc.cn

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

The following example shows how to set the base path in Java:spring-doc.cn

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

With a base path defined, the algorithm that assigns flow identifiers changes slightly. Flows are now assigned registry identifiers equal to the the path segment between their base path and their file name. For example, if a flow definition is located at /WEB-INF/hotels/booking/booking-flow.xml and the base path is /WEB-INF, the remaining path to this flow is hotels/booking, which becomes the flow ID.spring-doc.cn

A directory for each flow definition
It is a best practice to package each flow definition in a unique directory. This improves modularity, letting dependent resources be packaged with the flow definition. It also prevents two flows from having the same identifiers when using the convention.

If no base path is not specified or if the flow definition is directly on the base path, flow ID assignment from the filename (minus the extension) is used. For example, if a flow definition file is booking.xml, the flow identifier is simply booking.spring-doc.cn

Location patterns are particularly powerful when combined with a registry base path. Instead of the flow identifiers becoming *-flow, they are based on the directory path. The following example combines a base path with a flow location pattern in XML:spring-doc.cn

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

The following example combines a base path with a flow location pattern in Java:spring-doc.cn

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

In the preceding example, suppose you had flows located in the /user/login, /user/registration, /hotels/booking, and /flights/booking directories within WEB-INF. You would end up with flow IDs of user/login, user/registration, hotels/booking, and flights/booking, respectively.spring-doc.cn

18.3.6. Configuring FlowRegistry Hierarchies

You can use the parent attribute to link two flow registries together in a hierarchy. When the child registry is queried, if it cannot find the requested flow, it delegates to its parent.spring-doc.cn

The following example establishes a parent relationship for two flow registries in XML:spring-doc.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>

The following example establishes a parent relationship for two flow registries in Java:spring-doc.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. Configuring Custom FlowBuilder Services

You can use the flow-builder-services attribute (in XML) or the FlowBuilderServices object (in Java) to customize the services and settings used to build flows in a flow-registry. If no flow-builder-services element is specified, the default service implementations are used. When the element is specified, you need only reference the services you want to customize.spring-doc.cn

The following example shows how to create a custom flow builder service in XML:spring-doc.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" />

The following example shows how to create a custom flow builder service in Java:spring-doc.cn

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

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

The configurable services are the conversion-service, expression-parser, and view-factory-creator elements (in XML) and the ConversionService, ExpressionParser, and ViewFactoryCreator interfaces (in Java). These services are configured by referencing custom beans that you must define.spring-doc.cn

The following example shows how to define the configurable services in XML:spring-doc.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="..." />

The following example shows how to define the configurable services in Java:spring-doc.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() {
    // ...
}
Using the Conversion Service

You can use the conversion-service attribute (in XML) or the ConversionService interface (in Java) to customize the ConversionService used by the Web Flow system. Type conversion is used to convert from one type to another when required during flow execution, such as when processing request parameters, invoking actions, and so on. Many common object types (such as numbers, classes, and enums) are supported. However, you probably need to provide your own type conversion and formatting logic for custom data types. See Performing Type Conversion for important information on how to provide custom type conversion logic.spring-doc.cn

Using the Expression Parser

You can use the expression-parser attribute (in XML) or the ExpressionParser interface (in Java) to customize the ExpressionParser used by the Web Flow system. The default ExpressionParser uses the Unified Expression Language if available on the classpath. Otherwise, it uses the Spring Expression Language.spring-doc.cn

Using the View Factory Creator

You can use the view-factory-creator attribute (in XML) or the ViewFactoryCreator interface (in Java) to customize the ViewFactoryCreator used by the Web Flow system. The default ViewFactoryCreator produces Spring MVC view factories capable of rendering JSP, Velocity, and Freemarker views.spring-doc.cn

The configurable settings are development. These settings are global configuration attributes that you can apply during the flow construction process.spring-doc.cn

Enabling Development Mode

When you create a flow builder services object, you can turn on development mode. Development mode switches on hot-reloading of flow definition changes, including changes to dependent flow resources such as message bundles.spring-doc.cn

To turn on development mode in XML, set the development attribute on the flow-builder-services element to true. To turn on development mode in Java, use setDevelopment(true) on the FlowBuilderServices object.spring-doc.cn

18.4. Setting Flow Executor options

This section explores Flow Executor configuration options.spring-doc.cn

18.4.1. Attaching Flow Execution Listeners

You can use the flow-execution-listeners element (in XML) or the addFlowExecutionListener method (in Java) to register listeners that observe the lifecycle of flow executions.spring-doc.cn

The following example shows how to create flow execution listeners in XML:spring-doc.cn

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

The folloiwng example shows how to create flow execution listeners in Java:spring-doc.cn

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

You can also configure a listener to observe only certain flows.spring-doc.cn

The following example shows how to configure a listener to monitor only two flows in XML:spring-doc.cn

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

The following example shows how to configure a listener to monitor only two flows in Java:spring-doc.cn

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

18.4.2. Tuning Flow Execution Persistence

You can use the flow-execution-repository element (in XML) or the FlowExecutor interface (in Java) to tune flow execution persistence settings.spring-doc.cn

The following example tunes flow execution in XML:spring-doc.cn

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

The following example tunes flow execution in Java:spring-doc.cn

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

You can tune the max-executions attribute (in XML) to place a cap on the number of flow executions that can be created per user session. When the maximum number of executions is exceeded, the oldest execution is removed.spring-doc.cn

The max-executions attribute is per user session. That is, it works across instances of any flow definition.
Tuning max-execution-snapshots

You can tune the max-execution-snapshots attribute to place a cap on the number of history snapshots that can be taken per flow execution. To disable snapshotting, set this value to 0. To enable an unlimited number of snapshots, set this value to -1.spring-doc.cn

History snapshots enable browser back button support. When snapshotting is disabled, pressing the browser back button does not work. Doing so results in using an execution key that points to a snapshot that has not been recorded.