13. 渲染视图

本章介绍如何使用view-state元素来呈现流中的视图。spring-doc.cadn.net.cn

13.1. 定义视图状态

view-state元素定义了呈现视图并等待用户事件恢复的流步骤,如下所示:spring-doc.cadn.net.cn

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

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

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

流视图打包

13.2. 指定视图标识符

您可以使用view属性来显式指定要呈现的视图的 ID。spring-doc.cadn.net.cn

13.2.1. 流相对视图 ID

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

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

13.2.2. 绝对视图 ID

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

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

13.2.3. 逻辑视图 ID

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

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

有关如何与 MVC 集成的更多信息,请参阅 Spring MVC 集成部分ViewResolver基础设施。spring-doc.cadn.net.cn

13.3. 查看范围

一个view-state分配一个新的viewScope当它进入时。 您可以在view-state分配应该在状态持续时间内存在的变量。 此作用域对于作来自同一视图的一系列请求(通常是 Ajax 请求)的对象非常有用。 一个view-state销毁其viewScope当它退出时。spring-doc.cadn.net.cn

13.3.1. 分配视图变量

您可以使用var标记来声明视图变量。 与流变量一样,任何@Autowired当视图状态恢复时,将自动恢复引用。 以下列表声明了一个视图变量:spring-doc.cadn.net.cn

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

13.3.2. 分配一个viewScope变量

您可以使用on-render标记,在视图渲染之前从作结果中分配变量,如下所示:spring-doc.cadn.net.cn

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

13.3.3. 在视图作用域中作对象

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

on-render元素在视图呈现之前运行一个或多个作。 渲染作在初始渲染以及任何后续刷新(包括视图的任何部分重新渲染)上运行。 以下列表定义了on-render元素:spring-doc.cadn.net.cn

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

13.5. 绑定到模型

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

以下示例声明enterBookingDetailsbooking型:spring-doc.cadn.net.cn

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

模型可以是任何可访问范围内的对象,例如flowScopeviewScope. 指定model在发生视图事件时触发以下行为:spring-doc.cadn.net.cn

  1. 视图到模型绑定。在视图回发时,用户输入值会绑定到模型对象属性。spring-doc.cadn.net.cn

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

对于可以驱动视图状态转换的流事件,必须成功完成模型绑定。 如果模型绑定失败,则会重新呈现视图,以便用户修改其编辑内容。spring-doc.cadn.net.cn

13.6. 执行类型转换

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

13.6.1. 类型转换选项

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

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

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

此规则的唯一例外是命名转换器,您可以从binding元素中的view-state如下:spring-doc.cadn.net.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.cadn.net.cn

另请注意,现有的 Spring BindingDefaultConversionService不再注册任何默认转换器。 相反,Web Flow 现在依赖于 Spring 中的默认类型转换器和格式化程序。spring-doc.cadn.net.cn

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

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

在 Spring MVC 中,一个FormattingConversionService通过自定义 MVC 命名空间自动创建,如下所示:spring-doc.cadn.net.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/>

在内部,这是在FormattingConversionServiceFactoryBean,它注册一组默认的转换器和格式化程序。 您可以通过conversion-service属性,如下所示:spring-doc.cadn.net.cn

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

在 Web Flow 中,Spring Binding 的实例DefaultConversionService自动创建不注册任何转换器。 相反,它委托给FormattingConversionService满足所有类型转换需求的实例。 默认情况下,这是不一样的FormattingConversionServiceinstance 作为 Spring 中使用的实例。 但是,在您开始注册自己的格式化程序之前,这不会产生实际影响。spring-doc.cadn.net.cn

您可以自定义DefaultConversionService通过 flow-builder-services 元素在 Web Flow 中使用,如下所示:spring-doc.cadn.net.cn

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

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

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

    public class ApplicationConversionServiceFactoryBean extends FormattingConversionServiceFactoryBean {
    
        @Override
        protected void installFormatters(FormatterRegistry registry) {
            // ...
        }
    
    }
    
  2. 配置类以在 Spring MVC 中使用:spring-doc.cadn.net.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 流DefaultConversionService到同样applicationConversionServiceSpring MVC 中使用的 bean:spring-doc.cadn.net.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>

您也可以混合搭配。 您可以注册新的 SpringFormatter类型通过applicationConversionService. 您可以注册现有的 Spring BindingConverter类型通过defaultConversionService.spring-doc.cadn.net.cn

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

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

Spring 中的类型转换器,在org.springframework.core,用于任意两种对象类型之间的通用类型转换。 除了最简单的Converter类型,另外两个接口是ConverterFactoryGenericConverter.spring-doc.cadn.net.cn

Spring 中的格式化程序,在org.springframework.context,具有更专业的代表目的Object实例作为String实例。 这Formatter接口扩展了PrinterParser用于转换Object设置为String并将String变成一个Object.spring-doc.cadn.net.cn

Web 开发人员可能会发现Formatter接口最相关,因为它符合 Web 应用程序对类型转换的需求。spring-doc.cadn.net.cn

对象到对象转换是更具体的对象到字符串转换的推广。 事实上Formatters注册为GenericConverter类型与 Spring 的GenericConversionService,使它们与任何其他转换器相等。

13.6.5. 格式化注释

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

13.6.6. 使用日期

@DateTimeFormat注释意味着使用 Joda Time。如果类路径上存在,则会自动启用此注释的使用。默认情况下,Spring MVC 和 Web Flow 都不会注册任何其他日期格式化程序或转换器。因此,应用程序注册自定义格式化程序以指定打印和解析日期的默认方式非常重要。 这@DateTimeFormat另一方面,注释在需要偏离默认值时提供了更细粒度的控制。spring-doc.cadn.net.cn

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

13.7. 抑制绑定

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

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

13.8. 显式指定绑定

您可以使用binder元素来配置要应用数据绑定的确切模型属性集。 这使您可以限制每个视图的“允许字段”集。 不使用它可能会导致安全问题,具体取决于应用程序域和实际用户,因为默认情况下,如果未指定 binder 元素,则模型的所有公共属性都有资格通过视图进行数据绑定。 相比之下,当binder元素,则只允许显式配置的绑定。 以下示例使用binder元素:spring-doc.cadn.net.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>

每个绑定还可以应用转换器来格式化模型属性值,以便以自定义方式显示。 如果未指定转换器,则使用模型属性类型的默认转换器。 以下示例显示了两个binding元素与converter属性:spring-doc.cadn.net.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>

在前面的示例中,shortDate转换器绑定到checkinDatecheckoutDate性能。 您可以使用应用程序的ConversionService.spring-doc.cadn.net.cn

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

13.9. 验证模型

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

13.9.1. JSR-303 Bean 验证

Web Flow 提供了对 JSR-303 Bean Validation API 的内置支持,建立在 Spring MVC 中可用的等效支持之上。 要启用 JSR-303 验证,请使用 Spring MVC 的LocalValidatorFactoryBean如下:spring-doc.cadn.net.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.cadn.net.cn

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

部分验证

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

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

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

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

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

例如,给定org.example.MyModel带内部类型Group1Group2,提供简单的类型名称就足够了——也就是说,group1group2. 还可以提供完全限定的类型名称。spring-doc.cadn.net.cn

值为default具有特殊含义,并被转换为 Bean Validation 中的默认验证组:jakarta.validation.groups.Default.spring-doc.cadn.net.cn

您可以配置自定义ValidationHintResolver,如有必要,通过validationHintResolver属性的flow-builder-services元素,如下所示:spring-doc.cadn.net.cn

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

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

13.9.2. 编程验证

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

实现模型验证方法

在模型对象中定义验证逻辑是验证其状态的最简单方法。 一旦根据 Web Flow 约定构建了此类逻辑,Web Flow 就会在view-state回发生命周期。 Web 流约定让您通过以下方式构建模型验证逻辑view-state,允许您验证在该视图上可编辑的模型属性的子集。 为此,请创建一个名称为validate${state}哪里${state}是您的 IDview-state您希望对其运行验证。 以下示例执行模型验证:spring-doc.cadn.net.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());
        }
    }
}

在前面的示例中,当在enterBookingDetails view-state也就是说,正在编辑一个Booking模型时,Web Flow 会自动调用validateEnterBookingDetails(ValidationContext)方法,除非已禁止该转换的验证。 以下示例显示了这样的view-state:spring-doc.cadn.net.cn

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

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

实现验证器

执行编程验证的第二种方法是定义一个单独的对象,称为验证器,用于验证模型对象。 为此,首先创建一个名称具有模式${model}Validator哪里${model}是模型表达式的大写形式,例如Booking. 然后定义一个名称为validate${state}哪里${state}是您的 IDview-stateenterBookingDetails. 然后应该将该类部署为 Spring bean。 可以定义任意数量的验证方法。 以下示例定义了这样的验证器:spring-doc.cadn.net.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());
        }
    }
}

在前面的示例中,当在enterBookingDetails view-state也就是说,正在编辑一个Booking模型时,Web Flow 会自动调用validateEnterBookingDetails(Booking, ValidationContext)方法,除非已禁止该转换的验证。spring-doc.cadn.net.cn

验证器也可以接受 Spring MVCErrors对象,这是调用现有 Spring 验证器所必需的。spring-doc.cadn.net.cn

验证者必须注册为 Spring bean,使用${model}Validator命名约定,以自动检测和调用。 在前面的示例中,Spring 类路径扫描将检测到@Component并自动将其注册为名称为bookingValidator. 然后,任何时候booking模型需要验证,这个bookingValidator实例将被调用。spring-doc.cadn.net.cn

默认验证方法

验证器类还可以定义一个名为validate(按照惯例)与任何特定view-state. 以下示例定义了这样的方法:spring-doc.cadn.net.cn

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

在前面的代码示例中,validate每次类型为Booking已验证(除非已禁止该转换的验证)。如果需要,除了现有的特定于状态的方法之外,还可以调用默认方法。 请考虑以下示例:spring-doc.cadn.net.cn

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

在前面的代码示例中,validateEnterBookingDetails方法首先被调用。 默认值validate方法被调用。spring-doc.cadn.net.cn

13.9.3.ValidationContext接口

一个ValidationContext让您获得一个MessageContext在验证期间记录消息。 它还公开有关当前用户的信息,例如信号userEvent和当前用户的Principal身份。 您可以使用此信息根据UI中激活的按钮或链接或经过身份验证的人员自定义验证逻辑。 请参阅 API JavadocValidationContext了解更多信息。spring-doc.cadn.net.cn

13.10. 抑制验证

您可以使用validate属性来抑制特定视图事件的模型验证,如下所示:spring-doc.cadn.net.cn

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

在前面的示例中,数据绑定仍发生在back,但验证被禁止。spring-doc.cadn.net.cn

13.11. 定义视图转换

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

以下部分讨论如何实现视图转换。spring-doc.cadn.net.cn

13.11.1. 过渡作

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

如果过渡作调用纯 Java 方法,则调用的方法可能会返回一个布尔值,其值 (truefalse) 指示是应进行转换还是阻止运行。 一个方法还可以返回一个String其中文字值success,yestrue表示应该发生转换,任何其他值都表示相反。 可以使用此技术来处理服务层方法引发的异常。 以下示例调用调用服务并处理异常情况的作:spring-doc.cadn.net.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.cadn.net.cn

13.11.2. 全局转换

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

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

13.11.3. 事件处理程序

view-state,也可以定义没有目标的转换。此类转换称为“事件处理程序”。以下示例定义了此类转换:spring-doc.cadn.net.cn

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

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

13.11.4. 渲染片段

您可以使用render元素在处理事件后请求对当前视图进行部分重新渲染,如下所示:spring-doc.cadn.net.cn

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

fragments属性应引用要重新渲染的视图元素的 ID。 您可以通过用逗号分隔符分隔多个元素来指定要重新呈现的多个元素。spring-doc.cadn.net.cn

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

13.12. 使用消息

Spring Web Flow 的MessageContext是一个 API,用于在流执行过程中记录消息。 您可以将纯文本消息添加到上下文中,以及由 Spring 解析的国际化消息MessageSource. 消息可由视图呈现,并在流执行重定向中自动存活。 提供了三种不同的消息严重性:info,warningerror. 此外,方便MessageBuilder存在用于流畅地构建消息。spring-doc.cadn.net.cn

13.12.1. 添加纯文本消息

您可以向上下文添加纯文本消息。 以下示例显示了如何执行此作:spring-doc.cadn.net.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.cadn.net.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 访问的消息包中定义MessageSource. 要创建特定于流的消息包,请定义messages.properties流目录中的文件。 创建默认值messages.propertiesfile 和.properties每个附加文件Locale你需要支持。 以下示例定义了一些消息:spring-doc.cadn.net.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

在视图或流中,您还可以使用resourceBundleEL 变量,如下所示:spring-doc.cadn.net.cn

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

13.12.4. 了解系统生成的消息

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

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

booking.checkinDate.typeMismatch

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

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

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

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

13.13. 显示弹出窗口

您可以使用popup属性在模式弹出对话框中呈现视图,如下所示:spring-doc.cadn.net.cn

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

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

13.14. 视图回溯

默认情况下,当您退出视图状态并转换为新的视图状态时,您可以使用浏览器的后退按钮返回到以前的状态。 这些视图状态历史记录策略可通过使用history属性。spring-doc.cadn.net.cn

13.14.1. 丢弃历史记录

您可以将history属性设置为discard要防止回溯到视图,如下所示:spring-doc.cadn.net.cn

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

13.14.2. 使历史失效

您可以将history属性设置为invalidate以防止回溯到视图以及所有先前显示的视图,如下所示:spring-doc.cadn.net.cn

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