13. 渲染视图

本章介绍如何使用该元素在流中呈现视图。view-statespring-doc.cn

13.1. 定义视图状态

该元素定义流程的一个步骤,该步骤呈现视图并等待 user 事件恢复,如下所示:view-statespring-doc.cn

<view-state id="enterBookingDetails">
    <transition on="submit" to="reviewBooking" />
</view-state>

按照惯例,a 会将其 ID 映射到流所在目录中的视图模板。 例如,如果流本身位于目录中,则前面示例中的状态可能会呈现。view-state/WEB-INF/hotels/booking/enterBookingDetails.xhtml/WEB-INF/hotels/bookingspring-doc.cn

下图显示了一个示例目录结构,其中包含视图和其他资源,例如与其流定义位于同一位置的消息包:spring-doc.cn

流视图打包

13.2. 指定视图标识符

您可以使用该属性显式指定要呈现的视图的 ID。viewspring-doc.cn

13.2.1. 流相对视图 ID

视图 ID 可以是流程工作目录中查看资源的相对路径,如下所示:spring-doc.cn

<view-state id="enterBookingDetails" view="bookingDetails.xhtml">

13.2.2. 绝对视图 ID

视图 ID 可以是 webapp 根目录中视图资源的绝对路径,如下所示:spring-doc.cn

<view-state id="enterBookingDetails" view="/WEB-INF/hotels/booking/bookingDetails.xhtml">

13.2.3. 逻辑视图 ID

对于某些视图框架,例如 Spring MVC 的视图框架,视图 ID 也可能是由框架解析的逻辑标识符,如下所示:spring-doc.cn

<view-state id="enterBookingDetails" view="bookingDetails">

有关如何与 MVC 基础结构集成的更多信息,请参见 Spring MVC 集成部分。ViewResolverspring-doc.cn

13.3. 视图范围

A 在进入时分配一个 new。 您可以在 中引用此范围,以分配应在状态持续时间内存在的变量。 此范围对于从同一视图(通常是 Ajax 请求)的一系列请求中操作对象非常有用。 A 在退出时销毁其。view-stateviewScopeview-stateview-stateviewScopespring-doc.cn

13.3.1. 分配视图变量

您可以使用该标签来声明视图变量。 与 flow 变量一样,当视图状态恢复时,任何引用都会自动恢复。 下面的清单声明了一个 view 变量:var@Autowiredspring-doc.cn

<var name="searchCriteria" class="com.mycompany.myapp.hotels.SearchCriteria" />

13.3.2. 分配变量viewScope

在视图呈现之前,您可以使用该标签从操作结果中分配变量,如下所示:on-renderspring-doc.cn

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

13.3.3. 在 View Scope 中操作对象

视图范围内的对象通常是通过来自同一视图的一系列请求进行操作的。 在每次渲染之前,该列表都会在视图范围内更新。 异步事件处理程序修改当前数据页,然后请求重新呈现搜索结果片段。 以下示例浏览搜索结果列表:spring-doc.cn

<view-state id="searchResults">
    <on-render>
        <evaluate expression="bookingService.findHotels(searchCriteria)"
                  result="viewScope.hotels" />
    </on-render>
    <transition on="next">
        <evaluate expression="searchCriteria.nextPage()" />
        <render fragments="searchResultsFragment" />
    </transition>
    <transition on="previous">
        <evaluate expression="searchCriteria.previousPage()" />
        <render fragments="searchResultsFragment" />
    </transition>
</view-state>

13.4. 运行 Render Actions

该元素在视图呈现之前运行一个或多个操作。 渲染操作在初始渲染以及任何后续刷新(包括视图的任何部分重新渲染)上运行。 下面的清单定义了一个元素:on-renderon-renderspring-doc.cn

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

13.5. 绑定到模型

您可以使用该属性来声明视图绑定到的对象所在的模型。 此属性通常与呈现数据控件的视图 (如窗体) 结合使用。 它允许从模型对象上的元数据驱动表单数据绑定和验证行为。modelspring-doc.cn

下面的示例声明了一个操作模型的状态:enterBookingDetailsbookingspring-doc.cn

<view-state id="enterBookingDetails" model="booking">

模型可以是任何可访问范围(如 或 )中的对象。 指定 a 将在视图事件发生时触发以下行为:flowScopeviewScopemodelspring-doc.cn

  1. 视图到模型绑定。在查看回发时,用户输入值将绑定到您的模型对象属性。spring-doc.cn

  2. 模型验证。绑定后,如果模型对象需要验证,则调用该验证逻辑。spring-doc.cn

对于可以驱动生成视图状态转换的流程事件,模型绑定必须成功完成。 如果模型绑定失败,将重新渲染视图以允许用户修改其编辑。spring-doc.cn

13.6. 执行类型转换

当使用请求参数填充模型(通常称为数据绑定)时,在设置目标模型属性之前,需要进行类型转换来解析基于字符串的请求参数值。 默认类型转换可用于许多常见的 Java 类型,例如数字、基元、枚举和日期。 用户还可以为用户定义的类型注册自己的类型转换逻辑,并覆盖默认转换器。spring-doc.cn

13.6.1. 类型转换选项

从版本 2.1 开始, Spring Web Flow 使用类型转换格式化系统来满足几乎所有的类型转换需求。 以前,Web Flow 应用程序使用的类型转换机制与 Spring MVC 中的类型转换机制不同,后者依赖于抽象。 Spring 的类型转换实际上受到了 Web Flow 自己的类型转换系统的影响。 因此,Web Flow 用户应该发现使用 Spring 类型转换是很自然的。 此更改的另一个明显且重要的好处是,您现在可以在 Spring MVC 和 Spring Web Flow 中使用单一类型转换机制。java.beans.PropertyEditorspring-doc.cn

13.6.2. 升级到 Spring 3 类型转换和格式化

实际上,这对现有应用程序意味着什么?现有应用程序可能通过 Spring Binding 中的 available 的子类注册自己的 type 转换器。 这些转换器可以继续像以前一样注册。 它们已被改编为 Spring 类型,并在 Spring 实例中注册。 换句话说,现有的转换器是通过 Spring 的类型转换服务调用的。org.springframework.binding.convert.converters.ConverterDefaultConversionServiceGenericConverterorg.springframework.core.convert.ConversionServicespring-doc.cn

此规则的唯一例外是命名 converters,您可以从 中的元素引用 ,如下所示:bindingview-statespring-doc.cn

public class ApplicationConversionService extends DefaultConversionService {
    public ApplicationConversionService() {
        addDefaultConverters();
        addDefaultAliases();
        addConverter("customConverter", new CustomConverter());
    }
}
<view-state id="enterBookingDetails" model="booking">
    <binder>
        <binding property="checkinDate" required="true" converter="customConverter" />
    </binder>
</view-state>

命名转换器不受支持,也不能与 Spring 中提供的类型转换服务一起使用。 因此,此类转换器没有适应并继续像以前一样工作。 也就是说,它们不涉及 Spring 类型转换。 但是,此机制已被弃用,并且鼓励应用程序支持 Spring 类型转换和格式化功能。spring-doc.cn

还要注意,现有的 Spring Binding 不再注册任何默认转换器。 相反,Web Flow 现在依赖于 Spring 中的默认类型转换器和格式化程序。DefaultConversionServicespring-doc.cn

总之,Spring 类型转换和格式化现在几乎只用于 Web Flow。 尽管现有的应用程序应该可以在没有任何更改的情况下工作,但我们鼓励朝着统一应用程序的 Spring MVC 和 Spring Web Flow 部分的类型转换需求的方向发展。spring-doc.cn

13.6.3. 配置类型转换和格式化

在 Spring MVC 中,通过自定义 MVC 名称空间自动创建实例的实例,如下所示:FormattingConversionServicespring-doc.cn

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

	<mvc:annotation-driven/>

在内部,这是在 的帮助下完成的,它注册了一组默认的转换器和格式化程序。 您可以通过该属性自定义 Spring MVC 中使用的转换服务实例,如下所示:FormattingConversionServiceFactoryBeanconversion-servicespring-doc.cn

<mvc:annotation-driven conversion-service="applicationConversionService" />

在 Web Flow 中,会自动创建一个 Spring Binding 实例,该实例不注册任何转换器。 相反,它将委托给一个实例来满足所有类型转换需求。 默认情况下,这与 Spring 中使用的实例不同。 但是,在您开始注册自己的格式化程序之前,这不会产生实际区别。DefaultConversionServiceFormattingConversionServiceFormattingConversionServicespring-doc.cn

您可以通过 flow-builder-services 元素自定义 Web 流中使用的 ,如下所示:DefaultConversionServicespring-doc.cn

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

您可以执行以下操作来注册自己的格式化程序,以便在 Spring MVC 和 Spring Web Flow 中使用:spring-doc.cn

  1. 创建一个类来注册您的自定义格式化程序:spring-doc.cn

    public class ApplicationConversionServiceFactoryBean extends FormattingConversionServiceFactoryBean {
    
        @Override
        protected void installFormatters(FormatterRegistry registry) {
            // ...
        }
    
    }
    
  2. 配置类以在 Spring MVC 中使用:spring-doc.cn

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xsi:schemaLocation="
            http://www.springframework.org/schema/mvc
            https://www.springframework.org/schema/mvc/spring-mvc.xsd
            http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <mvc:annotation-driven conversion-service="applicationConversionService" />
    
        <!--
        	Alternatively if you prefer annotations for DI:
        	  1. Add @Component to the factory bean.
        	  2. Add a component-scan element (from the context custom namespace) here.
        	  3. Remove XML bean declaration below.
          -->
    
        <bean id="applicationConversionService" class="somepackage.ApplicationConversionServiceFactoryBean">
  3. 将 Web 流连接到 Spring MVC 中使用的同一 bean:DefaultConversionServiceapplicationConversionServicespring-doc.cn

        <webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices" ... />
    
        <webflow:flow-builder-services id="flowBuilderServices" conversion-service="defaultConversionService" ... />
    
        <bean id="defaultConversionService" class="org.springframework.binding.convert.service.DefaultConversionService">
        	<constructor-arg ref="applicationConversionSevice"/>
        </bean>

您也可以混合搭配。 您可以通过 . 您可以通过 .FormatterapplicationConversionServiceConverterdefaultConversionServicespring-doc.cn

13.6.4. 使用 Spring 类型转换和格式化

`` 需要了解的一个重要概念是类型转换器和格式化程序之间的区别。spring-doc.cn

Spring 中的类型转换器(如 中提供)用于任意两个对象类型之间的通用类型转换。 除了最简单的类型之外,其他两个接口是 和 。org.springframework.coreConverterConverterFactoryGenericConverterspring-doc.cn

Spring 中提供的格式化程序具有更专业的用途,即将实例表示为实例。 该接口扩展了 和 接口,用于将 an 转换为 a 并将 a 转换为 .org.springframework.contextObjectStringFormatterPrinterParserObjectStringStringObjectspring-doc.cn

Web 开发人员可能会发现该接口最相关,因为它符合 Web 应用程序进行类型转换的需要。Formatterspring-doc.cn

对象到对象转换是更具体的对象到字符串转换的泛化。 实际上,在 Spring's 中注册为类型,使它们等于任何其他转换器。FormattersGenericConverterGenericConversionService

13.6.5. 格式化注解

类型转换的最佳功能之一是能够使用注释以简洁的方式更好地控制格式。 您可以在模型属性和映射到请求的方法的参数上放置注释。 Spring 提供了两个 Comments( 和 ),但您可以创建自己的 Comments 并注册它们以及相关的格式逻辑。@Controller@NumberFormat@DateTimeFormatspring-doc.cn

13.6.6. 使用日期

注释暗示了 Joda Time 的使用。 如果 Classpath 上存在该 Comments,则会自动启用此 Comments 的使用。 默认情况下,Spring MVC 和 Web Flow 都不会注册任何其他日期格式化程序或转换器。 因此,应用程序必须注册自定义格式化程序以指定打印和解析日期的默认方式。 另一方面,注解在需要偏离默认值的地方提供更精细的控制。@DateTimeFormat@DateTimeFormatspring-doc.cn

有关使用 Spring 类型转换和格式设置的更多信息,请参阅 Spring 文档的相关部分。spring-doc.cn

13.7. 抑制绑定

您可以使用该属性来禁止特定视图事件的模型绑定和验证。 以下示例在事件发生时禁止绑定:bindcancelspring-doc.cn

<view-state id="enterBookingDetails" model="booking">
    <transition on="proceed" to="reviewBooking">
    <transition on="cancel" to="bookingCancelled" bind="false" />
</view-state>

13.8. 显式指定绑定

您可以使用该元素来配置要应用数据绑定的确切模型属性集。 这允许您限制每个视图的 “allowed fields” 集。 如果不这样做可能会导致安全问题,具体取决于应用程序域和实际用户,因为默认情况下,如果未指定 Binder 元素,则模型的所有公共属性都有资格由视图进行数据绑定。 相比之下,当指定 element 时,只允许显式配置的绑定。 以下示例使用元素:binderbinderbinderspring-doc.cn

<view-state id="enterBookingDetails" model="booking">
    <binder>
        <binding property="creditCard" />
        <binding property="creditCardName" />
        <binding property="creditCardExpiryMonth" />
        <binding property="creditCardExpiryYear" />
    </binder>
    <transition on="proceed" to="reviewBooking" />
    <transition on="cancel" to="cancel" bind="false" />
</view-state>

每个绑定还可以应用转换器来格式化模型属性值,以便以自定义方式显示。 如果未指定转换器,则使用 model 属性类型的默认转换器。 以下示例显示了两个具有 attributes 的元素:bindingconverterspring-doc.cn

<view-state id="enterBookingDetails" model="booking">
    <binder>
        <binding property="checkinDate" converter="shortDate" />
        <binding property="checkoutDate" converter="shortDate" />
        <binding property="creditCard" />
        <binding property="creditCardName" />
        <binding property="creditCardExpiryMonth" />
        <binding property="creditCardExpiryYear" />
    </binder>
    <transition on="proceed" to="reviewBooking" />
    <transition on="cancel" to="cancel" bind="false" />
</view-state>

在前面的示例中,转换器绑定到 and 属性。 您可以使用应用程序的 .shortDatecheckinDatecheckoutDateConversionServicespring-doc.cn

如果用户提供的值在表单回发时为 null,则每个绑定还可以应用必需的检查以生成验证错误,如下所示:spring-doc.cn

<view-state id="enterBookingDetails" model="booking">
    <binder>
        <binding property="checkinDate" converter="shortDate" required="true" />
        <binding property="checkoutDate" converter="shortDate" required="true" />
        <binding property="creditCard" required="true" />
        <binding property="creditCardName" required="true" />
        <binding property="creditCardExpiryMonth" required="true" />
        <binding property="creditCardExpiryYear" required="true" />
    </binder>
    <transition on="proceed" to="reviewBooking">
    <transition on="cancel" to="bookingCancelled" bind="false" />
</view-state>

在前面的示例中,所有绑定都是必需的。 如果绑定了一个或多个空白输入值,则会生成验证错误,并且视图会使用这些错误重新呈现。spring-doc.cn

13.9. 验证模型

模型验证由针对模型对象指定的约束驱动。 Web Flow 支持以编程方式以及使用 JSR-303 Bean Validation 注解以声明方式强制执行此类约束。spring-doc.cn

13.9.1. JSR-303 Bean 验证

Web Flow 为 JSR-303 Bean 验证 API 提供了内置支持,构建在 Spring MVC 中提供的等效支持之上。 要启用 JSR-303 验证,请使用 Spring MVC 的 flow-builder-services 配置,如下所示:LocalValidatorFactoryBeanspring-doc.cn

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

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

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />

有了前面的示例,配置的验证器将在数据绑定后应用于所有模型属性。spring-doc.cn

请注意,JSR-303 bean 验证和按约定验证(将在下一节中解释)并不是互斥的。 换句话说,Web Flow 应用所有可用的验证机制。spring-doc.cn

部分验证

JSR-303 Bean Validation 支持通过验证组进行部分验证。 以下示例定义部分验证:spring-doc.cn

@NotNull
@Size(min = 2, max = 30, groups = State1.class)
private String name;

在流程定义中,您可以在视图状态或转换上指定验证提示,这些提示将解析为验证组。 以下示例定义验证提示:spring-doc.cn

<view-state id="state1" model="myModel" validation-hints="'group1,group2'">

该属性是一个表达式,在前面的示例中,该表达式解析为由两个提示组成的逗号分隔:和 。A 用于解决这些提示。 默认情况下,used 尝试将这些字符串解析为基于类的 bean 验证组。 为此,它会在模型或其父级中查找匹配的内部类型。validation-hintsStringgroup1group2ValidationHintResolverBeanValidationHintResolverspring-doc.cn

例如,给定内部类型 和 ,则提供简单的类型名称就足够了 — 即 和 。 您还可以提供完全限定的类型名称。org.example.MyModelGroup1Group2group1group2spring-doc.cn

值为 of 的提示具有特殊含义,并转换为 Bean Validation 中的默认验证组: 。defaultjakarta.validation.groups.Defaultspring-doc.cn

如有必要,您可以通过元素的属性配置 custom ,如下所示:ValidationHintResolvervalidationHintResolverflow-builder-servicesspring-doc.cn

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

<webflow:flow-builder-services id="flowBuilderServices" validator=".." validation-hint-resolver=".." />

13.9.2. 编程验证

有两种方法可以以编程方式执行模型验证。 第一种是在模型对象中实现验证逻辑。 第二种是实现外部 . 这两种方法都为您提供了记录错误消息和访问有关当前用户的信息。ValidatorValidationContextspring-doc.cn

实现模型验证方法

在模型对象中定义验证逻辑是验证其状态的最简单方法。 一旦根据 Web 流约定构建了此类逻辑,Web Flow 就会在回发生命周期中自动调用该逻辑。 Web 流约定允许您通过 来构建模型验证逻辑,从而允许您验证该视图上可编辑的模型属性的子集。 为此,请创建一个名称为 的公共方法,其中 是要为其运行验证的 ID 的 ID。 以下示例执行模型验证:view-stateview-statevalidate${state}${state}view-statespring-doc.cn

public class Booking {
    private Date checkinDate;
    private Date checkoutDate;
    ...

    public void validateEnterBookingDetails(ValidationContext context) {
        MessageContext messages = context.getMessageContext();
        if (checkinDate.before(today())) {
            messages.addMessage(new MessageBuilder().error().source("checkinDate").
                defaultText("Check in date must be a future date").build());
        } else if (!checkinDate.before(checkoutDate)) {
            messages.addMessage(new MessageBuilder().error().source("checkoutDate").
                defaultText("Check out date must be later than check in date").build());
        }
    }
}

在前面的示例中,当在编辑模型中触发转换时,Web 流会自动调用该方法,除非已禁止对该转换进行验证。 以下示例显示了这样的 :enterBookingDetailsview-stateBookingvalidateEnterBookingDetails(ValidationContext)view-statespring-doc.cn

<view-state id="enterBookingDetails" model="booking">
    <transition on="proceed" to="reviewBooking">
</view-state>

您可以定义任意数量的验证方法。 通常,流会编辑一系列视图上的模型。 在这种情况下,您将为需要运行 validation 的每个 Bean 定义一个 validate 方法。view-statespring-doc.cn

实现验证器

执行编程验证的第二种方法是定义一个单独的对象,称为 validator,用于验证您的模型对象。 为此,请首先创建一个 name 具有 pattern 的类,其中 是模型表达式的大写形式,例如 . 然后定义一个名称为 的公共方法,其中 是 的 ID,例如 。 然后,该类应部署为 Spring Bean。 可以定义任意数量的验证方法。 以下示例定义了这样的验证器:${model}Validator${model}Bookingvalidate${state}${state}view-stateenterBookingDetailsspring-doc.cn

@Component
public class BookingValidator {
    public void validateEnterBookingDetails(Booking booking, ValidationContext context) {
        MessageContext messages = context.getMessageContext();
        if (booking.getCheckinDate().before(today())) {
            messages.addMessage(new MessageBuilder().error().source("checkinDate").
                defaultText("Check in date must be a future date").build());
        } else if (!booking.getCheckinDate().before(booking.getCheckoutDate())) {
            messages.addMessage(new MessageBuilder().error().source("checkoutDate").
                defaultText("Check out date must be later than check in date").build());
        }
    }
}

在前面的示例中,当在编辑模型中触发转换时,Web 流会自动调用该方法,除非已禁止对该转换进行验证。enterBookingDetailsview-stateBookingvalidateEnterBookingDetails(Booking, ValidationContext)spring-doc.cn

验证器还可以接受 Spring MVC 对象,这是调用现有 Spring 验证器所必需的。Errorsspring-doc.cn

验证器必须注册为 Spring bean,采用命名约定,才能被自动检测和调用。 在前面的示例中, Spring 类路径扫描将检测 并自动将其注册为名称为 的 bean。 然后,每当需要验证模型时,都会为您调用此实例。${model}Validator@ComponentbookingValidatorbookingbookingValidatorspring-doc.cn

默认验证方法

验证器类还可以定义一个调用的方法,该方法不与任何特定的 . 以下示例定义了这样一种方法:validateview-statespring-doc.cn

@Component
public class BookingValidator {
    public void validate(Booking booking, ValidationContext context) {
        //...
    }
}

在前面的代码示例中,每次验证 type of model 时都会调用 method (除非已禁止验证该转换)。如果需要,除了现有的特定于状态的方法之外,还可以调用 default 方法。 请考虑以下示例:validateBookingspring-doc.cn

@Component
public class BookingValidator {
    public void validate(Booking booking, ValidationContext context) {
        //...
    }
    public void validateEnterBookingDetails(Booking booking, ValidationContext context) {
        //...
    }
}

在上面的代码示例中,首先调用该方法。 默认方法称为 next。validateEnterBookingDetailsvalidatespring-doc.cn

13.9.3. 界面ValidationContext

A 允许您获取 a 以在验证期间记录消息。 它还公开有关当前用户的信息,例如发出信号和当前用户的身份。 您可以使用此信息根据 UI 中激活的按钮或链接或经过身份验证的用户来自定义验证逻辑。 有关更多信息,请参阅 ValidationContext 的 API Javadoc。ValidationContextMessageContextuserEventPrincipalspring-doc.cn

13.10. 抑制验证

您可以使用该属性来禁止对特定视图事件进行模型验证,如下所示:validatespring-doc.cn

<view-state id="chooseAmenities" model="booking">
    <transition on="proceed" to="reviewBooking">
    <transition on="back" to="enterBookingDetails" validate="false" />
</view-state>

在前面的示例中,数据绑定仍发生在 上,但会抑制验证。backspring-doc.cn

13.11. 定义视图过渡

您可以定义一个或多个元素来处理视图上可能发生的用户事件。 过渡可能会将用户带到另一个视图,或者它可以运行一个动作并重新渲染当前视图。 在处理 Ajax 事件时,过渡也可能请求渲染视图的各个部分(称为“片段”)。 最后,您还可以定义在所有视图之间共享的 “全局” 过渡。transitionspring-doc.cn

以下各节讨论如何实现视图转换。spring-doc.cn

13.11.1. 过渡动作

转换可以在运行之前调用一个或多个操作。 这些操作可能会返回错误结果,以防止转换退出当前 . 如果出现错误结果,视图会重新呈现,并应向用户显示相应的消息。view-stateview-statespring-doc.cn

如果转换操作调用普通 Java 方法,则调用的方法可能会返回一个布尔值,其值 ( 或 ) 指示是应该进行转换还是阻止运行。 方法还可以返回 where 文本值 , , 或指示应发生转换,而任何其他值则表示相反。 您可以使用此技术来处理服务层方法引发的异常。 以下示例调用调用服务并处理异常情况的操作:truefalseStringsuccessyestruespring-doc.cn

<transition on="submit" to="bookingConfirmed">
    <evaluate expression="bookingAction.makeBooking(booking, messageContext)" />
</transition>
public class BookingAction {
   public boolean makeBooking(Booking booking, MessageContext context) {
       try {
           bookingService.make(booking);
           return true;
       } catch (RoomNotAvailableException e) {
           context.addMessage(new MessageBuilder().error().
               .defaultText("No room is available at this hotel").build());
           return false;
       }
   }
}

当转换上定义了多个操作时,如果一个操作返回错误结果,则不会执行集中的其余操作。 如果需要确保一个转换操作的结果不会影响另一个转换操作的执行,请定义一个转换操作,该操作调用封装所有操作逻辑的方法。spring-doc.cn

13.11.2. 全局转换

您可以使用流的元素创建应用于所有视图的过渡。 全局过渡通常用于处理作为布局一部分的全局菜单链接。 下面的示例定义了一个元素:global-transitionsglobal-transitionspring-doc.cn

<global-transitions>
    <transition on="login" to="login" />
    <transition on="logout" to="logout" />
</global-transitions>

13.11.3. 事件处理程序

从 中,您还可以定义不带目标的过渡。 此类转换称为 “事件处理程序”。 以下示例定义了这样的过渡:view-statespring-doc.cn

<transition on="event">
    <!-- Handle event -->
</transition>

这些事件处理程序不会更改流的状态。 它们执行自己的操作并重新渲染当前视图或当前视图的一个或多个片段。spring-doc.cn

13.11.4. 渲染片段

在处理事件后,您可以使用过渡中的元素请求部分重新渲染当前视图,如下所示:renderspring-doc.cn

<transition on="next">
    <evaluate expression="searchCriteria.nextPage()" />
    <render fragments="searchResultsFragment" />
</transition>

该属性应引用您希望重新渲染的视图元素的 ID。 您可以通过用逗号分隔符分隔多个元素来指定要重新渲染的元素。fragmentsspring-doc.cn

这种部分呈现通常与 Ajax 发出信号的事件一起使用,以更新视图的特定区域。spring-doc.cn

13.12. 使用消息

Spring Web Flow 是一个 API,用于在流执行过程中记录消息。 您可以将纯文本消息添加到上下文中,以及由 Spring 解析的国际化消息。 消息可由视图呈现,并自动在流执行重定向后继续存在。 提供了三种不同的消息严重性:、 和 。 此外,还存在一种方便的方式,用于流畅地构造消息。MessageContextMessageSourceinfowarningerrorMessageBuilderspring-doc.cn

13.12.1. 添加纯文本消息

您可以将纯文本消息添加到上下文中。 以下示例显示了如何执行此操作:spring-doc.cn

MessageContext context = ...
MessageBuilder builder = new MessageBuilder();
context.addMessage(builder.error().source("checkinDate")
    .defaultText("Check in date must be a future date").build());
context.addMessage(builder.warn().source("smoking")
    .defaultText("Smoking is bad for your health").build());
context.addMessage(builder.info()
    .defaultText("We have processed your reservation - thank you and enjoy your stay").build());

13.12.2. 添加国际化消息

您可以将国际化(即本地化)消息添加到上下文中。 以下示例显示了如何执行此操作:spring-doc.cn

MessageContext context = ...
MessageBuilder builder = new MessageBuilder();
context.addMessage(builder.error().source("checkinDate").code("checkinDate.notFuture").build());
context.addMessage(builder.warn().source("smoking").code("notHealthy")
    .resolvableArg("smoking").build());
context.addMessage(builder.info().code("reservationConfirmation").build());

13.12.3. 使用消息包

国际化消息在 Spring 访问的消息包中定义。 要创建特定于流的消息捆绑包,请在流的目录中定义文件。 创建一个默认文件,并为您需要支持的每个附加文件创建一个文件。 以下示例定义了一些消息:MessageSourcemessages.propertiesmessages.properties.propertiesLocalespring-doc.cn

#messages.properties
checkinDate=Check in date must be a future date
notHealthy={0} is bad for your health
reservationConfirmation=We have processed your reservation - thank you and enjoy your stay

在视图或流中,您还可以使用 EL 变量访问消息资源,如下所示:resourceBundlespring-doc.cn

<h:outputText value="#{resourceBundle.reservationConfirmation}" />

13.12.4. 了解系统生成的消息

Web Flow 本身会在多个位置生成要向用户显示的消息。 发生这种情况的一个重要位置是在视图到模型的数据绑定期间。 当发生绑定错误(例如类型转换错误)时,Web Flow 会将该错误映射到从资源包中自动检索的消息。 为了查找要显示的消息,Web Flow 会尝试包含绑定错误代码和目标属性名称的资源键。spring-doc.cn

例如,考虑绑定到对象的属性。 假设用户键入了一个字母字符串。 在这种情况下,会引发类型转换错误。 Web Flow 将错误代码映射到消息,方法是首先查询资源包中具有以下键的消息:checkinDateBookingtypeMismatchspring-doc.cn

booking.checkinDate.typeMismatch

键的第一部分是模型类的短名称。 键的第二部分是属性名称。 第三部分是错误代码。 这允许在模型属性的绑定失败时查找唯一消息以向用户显示。 此类消息可能会说:spring-doc.cn

booking.checkinDate.typeMismatch=The check in date must be in the format yyyy-mm-dd.

如果找不到该形式的此类资源密钥,则尝试更通用的密钥。 此键是错误代码。 属性的字段名称作为 message 参数提供,如下所示:spring-doc.cn

typeMismatch=The {0} field is of the wrong type.

13.13. 显示弹出窗口

您可以使用该属性在模态弹出对话框中呈现视图,如下所示:popupspring-doc.cn

<view-state id="changeSearchCriteria" view="enterSearchCriteria.xhtml" popup="true">

将 Web Flow 与 Spring Javascript 库一起使用时,不需要客户端代码即可显示弹出窗口。 Web Flow 向客户端发送响应,以请求从弹出窗口重定向到视图,客户端接受该请求。spring-doc.cn

13.14. View 回溯

默认情况下,当您退出视图状态并转换到新的视图状态时,您可以使用浏览器后退按钮返回到之前的状态。 这些视图状态历史记录策略可使用 属性按转换进行配置。historyspring-doc.cn

13.14.1. 丢弃历史记录

您可以将该属性设置为以防止回溯到视图,如下所示:historydiscardspring-doc.cn

<transition on="cancel" to="bookingCancelled" history="discard">

13.14.2. 使历史记录无效

您可以将该属性设置为以防止回溯到视图以及以前显示的所有视图,如下所示:historyinvalidatespring-doc.cn

<transition on="confirm" to="bookingConfirmed" history="invalidate">