21. JSF整合

Spring Web Flow 提供了一个 JavaServer Faces(JSF)集成,允许你将 JSF UI 组件模型与 Spring Web Flow 控制器一起使用。 Web Flow 还提供 Spring Security 标签库,供 JSF 环境中使用。 详情请参见使用 Spring Security面贴标签库spring-doc.cadn.net.cn

Spring Web Flow 4.0 需要 JSF 4.1 或更高版本。spring-doc.cadn.net.cn

21.1. 配置web.xml

第一步是将请求路由到调度器服务web.xml文件。 在下面的例子中,我们将所有以 开头的 URL 映射起来/Spring/给servlet。 servlet 需要配置。 一初始参数在servlet中用于传递contextConfigLocation. 这是你Web应用Spring配置的位置。 以下列表展示了配置详情:spring-doc.cadn.net.cn

<servlet>
	<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/web-application-config.xml</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
	<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
	<url-pattern>/spring/*</url-pattern>
</servlet-mapping>

为了让JSF正确引导,面圈必须配置于web.xml这通常是这样,尽管使用 JSF 配合 Spring Web Flow 时,通常不需要通过它路由请求。 以下列表展示了配置详情:spring-doc.cadn.net.cn

<!-- Just here so the JSF implementation can initialize. *Not* used at runtime. -->
<servlet>
	<servlet-name>Faces Servlet</servlet-name>
	<servlet-class>jakarta.faces.webapp.FacesServlet</servlet-class>
	<load-on-startup>1</load-on-startup>
</servlet>

<!-- Just here so the JSF implementation can initialize -->
<servlet-mapping>
	<servlet-name>Faces Servlet</servlet-name>
	<url-pattern>*.faces</url-pattern>
</servlet-mapping>

使用Facelet代替JSP通常需要以下元素web.xml:spring-doc.cadn.net.cn

!-- Use JSF view templates saved as *.xhtml, for use with Facelets -->
<context-param>
	<param-name>jakarta.faces.DEFAULT_SUFFIX</param-name>
	<param-value>.xhtml</param-value>
</context-param>

21.2. 配置用于 JSF 的网页流

本节解释如何用 JSF 配置 Web Flow。 支持Java和XML配置。 以下示例配置为 Web Flow 和 JSF 的 XML 格式: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:webflow="http://www.springframework.org/schema/webflow-config"
	xmlns:faces="http://www.springframework.org/schema/faces"
	si: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
		http://www.springframework.org/schema/faces
		https://www.springframework.org/schema/faces/spring-faces.xsd">

	<!-- Executes flows: the central entry point into the Spring Web Flow system -->
	<webflow:flow-executor id="flowExecutor">
		<webflow:flow-execution-listeners>
			<webflow:listener ref="facesContextListener"/>
		</webflow:flow-execution-listeners>
	</webflow:flow-executor>

	<!-- The registry of executable flow definitions -->
	<webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices" base-path="/WEB-INF">
		<webflow:flow-location-pattern value="**/*-flow.xml" />
	</webflow:flow-registry>

	<!-- Configures the Spring Web Flow JSF integration -->
	<faces:flow-builder-services id="flowBuilderServices" />

	<!-- A listener maintain one FacesContext instance per Web Flow request. -->
	<bean id="facesContextListener"
		class="org.springframework.faces.webflow.FlowFacesContextLifecycleListener" />

</beans>

以下示例在 Java 配置中也做了同样的作:spring-doc.cadn.net.cn

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.faces.config.*;

@Configuration
public class WebFlowConfig extends AbstractFacesFlowConfiguration {

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

    @Bean
    public FlowDefinitionRegistry flowRegistry() {
        return getFlowDefinitionRegistryBuilder()
                .setBasePath("/WEB-INF")
                .addFlowLocationPattern("**/*-flow.xml").build();
		}
}

主要点包括安装FlowFacesContextLifecycleListener那是一颗面孔上下文在Web流请求期间,以及使用流量-构建器-服务来自面临自定义命名空间,用于配置JSF环境的渲染。spring-doc.cadn.net.cn

在JSF环境中,你还需要以下与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:faces="http://www.springframework.org/schema/faces"
		 xsi:schemaLocation="
			 http://www.springframework.org/schema/beans
			 https://www.springframework.org/schema/beans/spring-beans.xsd
			 http://www.springframework.org/schema/faces
			 https://www.springframework.org/schema/faces/spring-faces.xsd">

	<faces:resources />

	<bean class="org.springframework.faces.webflow.JsfFlowHandlerAdapter">
		<property name="flowExecutor" ref="flowExecutor" />
	</bean>

</beans>

资源自定义命名空间元素将 JSF 资源请求委托给 JSF 资源 API。 这JsfFlowHandlerAdapter流量处理适配器通常与Web Flow一起使用。 该适配器通过JsfAjaxHandler而不是SpringJavaScriptAjaxHandler.spring-doc.cadn.net.cn

当你使用 Java 配置时,抽象面流配置基类会自动注册JsfResourceRequestHandler,所以没有更多可做的了。spring-doc.cadn.net.cn

21.3. 取代JSF管理的Beans设施

当你用 JSF 配合 Spring Web Flow 时,你可以完全用 Web Flow 管理变量和 Spring 管理的 Beans 来完全替代 JSF 管理的 Bean 功能。 它通过明确的钩子来初始化和执行你的域模型,给你对托管对象生命周期的控制权大大提升。 此外,既然你大概已经在业务层用 Spring,它减少了维护两个不同托管 Bean 模型的概念负担。spring-doc.cadn.net.cn

如果你纯粹做JSF开发,你可能会很快发现请求范围的寿命不够长,无法存储驱动复杂事件驱动视图的对话模型对象。 在 JSF 中,通常的选择是先将内容放入会话范围,但额外需要清理对象,才能进入应用的另一个视图或功能区域。 真正需要的是一个介于请求和会话范围之间的托管范围。 JSF提供闪烁和视野示波器,可通过程序访问UIViewRoot.getViewMap(). Spring Web Flow 提供闪回、视图、流和对话等功能。 这些示波器通过JSF变量解析器无缝集成,并在所有JSF应用中工作相同。spring-doc.cadn.net.cn

21.3.1. 使用流变量

声明和管理模型最简单、最自然的方式是使用流变量。 你可以在流程开始时声明这些变量,具体如下:spring-doc.cadn.net.cn

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

然后你可以通过EL在流程的JSF视图模板中引用该变量,具体如下:spring-doc.cadn.net.cn

<h:inputText id="searchString" value="#{searchCriteria.searchString}"/>

注意,引用模板时不需要在变量前加上作用域(不过如果需要更具体也可以)。 和标准的 JSF 豆子一样,所有可用的作用域都会被搜索匹配的变量,所以你可以在流量定义中更改变量的范围,而无需修改引用它的 EL 表达式。spring-doc.cadn.net.cn

你还可以定义视图实例变量,这些变量的作用域对应当前视图,切换到另一个视图时会自动清理。 这在 JSF 中非常有用,因为视图通常设计为处理多个页面内事件,跨多个请求后再切换到其他视图。spring-doc.cadn.net.cn

要定义视图实例变量,可以使用VAR元素在视图状态定义如下:spring-doc.cadn.net.cn

<view-state id="enterSearchCriteria">
	<var name="searchCriteria" class="com.mycompany.myapp.hotels.search.SearchCriteria"/>
</view-state>

21.3.2. 使用带瞄准镜的春豆

虽然定义自动连接的流程实例变量提供了良好的模块化和可读性,但有时你可能会想使用Spring容器的其他功能,比如面向切面编程(AOP)。 在这种情况下,你可以在春季中定义豆子应用上下文并赋予其特定的网页流域,具体如下:spring-doc.cadn.net.cn

<bean id="searchCriteria" class="com.mycompany.myapp.hotels.search.SearchCriteria" scope="flow"/>

这种方法的主要区别在于,豆子直到首次通过EL表达式访问时才会被完全初始化。 这种通过EL进行的懒惰实例化,与JSF管理豆子通常的分配方式非常相似。spring-doc.cadn.net.cn

21.3.3.作模型

在视图渲染前先初始化模型(例如从数据库加载持久实体)的需求相当常见,但JSF本身并未提供任何方便的初始化钩子。 流定义语言通过其动作为 提供了自然的便利性。 Spring Web Flow 为将动作结果转换为 JSF 专用数据结构提供了一些额外的便利。 以下示例展示了如何实现:spring-doc.cadn.net.cn

<on-render>
	<evaluate expression="bookingService.findBookings(currentUser.name)"
				result="viewScope.bookings" result-type="dataModel" />
</on-render>

前述例子取了bookingService.findBookings并用自定义的JSF数据模型包裹,使该列表可以在标准的JSF DataTable组件中使用,具体如下:spring-doc.cadn.net.cn

<h:dataTable id="bookings" styleClass="summary" value="#{bookings}" var="booking"
			rendered="#{bookings.rowCount > 0}">
	<h:column>
		<f:facet name="header">Name</f:facet>
		#{booking.hotel.name}
	</h:column>
	<h:column>
	<f:facet name="header">Confirmation number</f:facet>
		#{booking.id}
		</h:column>
	<h:column>
		<f:facet name="header">Action</f:facet>
		<h:commandLink id="cancel" value="Cancel" action="cancelBooking" />
	</h:column>
</h:dataTable>

21.3.4. 数据模型实现

在前文示例中,result-type=“dataModel”结果是预订名单<>有个习俗数据模型类型。 习俗数据模型提供了额外的便利,比如可序列化以超出请求范围的存储,以及访问EL表达式中当前选择的行。 例如,在后期回发时,从一个视图中,动作事件是由组件在数据表你可以对所选行的模型实例采取以下作:spring-doc.cadn.net.cn

<transition on="cancelBooking">
	<evaluate expression="bookingService.cancelBooking(bookings.selectedRow)" />
</transition>

Spring Web Flow 提供了两种自定义数据模型类型:OneSelectionTrackingListDataModelManySelectionTrackingListDataModel. 顾名思义,它们会跟踪一行或多行选中的行。 这是在SelectionTrackingActionListener监听器,响应JSF动作事件并调用相应的方法SelectionAware数据模型用于记录当前点击的行。spring-doc.cadn.net.cn

要理解这是如何配置的,请记住FacesConversionService寄存器A数据模型转换器针对该别名dataModel启动时。 什么时候result-type=“dataModel”在流量定义中使用时,它会导致数据模型转换器被使用。 转换器随后对给定的 进行包裹列表其中一个实例为OneSelectionTrackingListDataModel. 使用ManySelectionTrackingListDataModel你需要注册自己的自定义转换器。spring-doc.cadn.net.cn

21.4. 利用春季网页流处理JSF活动

Spring Web Flow 允许你以解耦的方式处理 JSF 动作事件,无需在 Java 代码中直接依赖 JSF API。 事实上,这些事件通常可以在流定义语言中完全处理,无需任何自定义的Java动作代码。 这使得开发过程更加敏捷,因为在布线事件中作的工件(JSF 视图模板和 SWF 流程定义)可以立即刷新,无需构建和重新部署整个应用程序。spring-doc.cadn.net.cn

21.4.1. 处理JSF页面内动作事件

JSF中一个简单但常见的情况是需要发出信号,导致模型作,然后重新显示相同视图以反映模型的变化状态。 流定义语言对此有特别支持,在过渡元素。spring-doc.cadn.net.cn

一个很好的例子是分页列表结果表。 假设你只想加载并显示大型结果列表中的一部分,并让用户浏览结果。 首字母视图状态加载和显示列表的定义如下:spring-doc.cadn.net.cn

<view-state id="reviewHotels">
	<on-render>
		<evaluate expression="bookingService.findHotels(searchCriteria)"
					result="viewScope.hotels" result-type="dataModel" />
	</on-render>
</view-state>

你可以构建一个JSF数据表来显示当前情况酒店列出并放置更多结果表格下方有链接,如下:spring-doc.cadn.net.cn

<h:commandLink id="nextPageLink" value="More Results" action="next"/>

commandLink信号 a下一个其事件行动属性。 然后你可以通过在视图状态定义如下:spring-doc.cadn.net.cn

<view-state id="reviewHotels">
	<on-render>
		<evaluate expression="bookingService.findHotels(searchCriteria)"
			result="viewScope.hotels" result-type="dataModel" />
	</on-render>
	<transition on="next">
		<evaluate expression="searchCriteria.nextPage()" />
	</transition>
</view-state>

来,你来处理下一个通过增加页数来事件检索标准实例。 这渲染时随后再次调用动作,更新后的条件,使下一页结果加载到数据模型. 同样的视图被重新渲染,因为没有属性过渡元素,模型的变化会反映在视图中。spring-doc.cadn.net.cn

21.4.2. 处理JSF行动事件

页面内事件之外的下一个逻辑层级是需要导航到另一个视图的事件,并在过程中对模型进行一定的作。 用纯JSF实现这一点需要在faces-config.xml以及可能在JSF管理的豆中加入一些中间的Java代码(这两项任务都需要重新部署)。使用流定义语言,你可以在一个地方简洁地处理此类情况,类似于处理页面内事件的方式。spring-doc.cadn.net.cn

继续我们作分页结果列表的用例,假设我们希望每一行都显示在数据表包含该行实例详细页面的链接。 你可以在表格中添加一列,包含以下内容commandLink分量如下:spring-doc.cadn.net.cn

<h:commandLink id="viewHotelLink" value="View Hotel" action="select"/>

这会提升选择事件,你可以通过添加另一个事件来处理过渡元素视图状态如下:spring-doc.cadn.net.cn

<view-state id="reviewHotels">
	<on-render>
		<evaluate expression="bookingService.findHotels(searchCriteria)"
			result="viewScope.hotels" result-type="dataModel" />
	</on-render>
	<transition on="next">
		<evaluate expression="searchCriteria.nextPage()" />
	</transition>
	<transition on="select" to="reviewHotel">
			<set name="flowScope.hotel" value="hotels.selectedRow" />
	</transition>
</view-state>

这里,选择事件通过将当前选择的酒店实例从数据表将其纳入流域,以便被酒店评论 视图状态.spring-doc.cadn.net.cn

21.4.3. 执行模型验证

JSF提供了有用的工具,可在模型变更前验证现场层面的输入。 然而,当更新应用后需要在模型层面进行更复杂的验证时,通常需要在托管豆中添加更多自定义代码到JSF动作方法。 此类验证通常是领域模型本身的责任,但很难将错误消息传回视图,否则会对你的领域层的JSF API产生不良依赖。spring-doc.cadn.net.cn

通过Web Flow,你可以使用通用和底层消息上下文在你的业务代码中,添加的任何消息随后都可以被面孔上下文在渲染时。spring-doc.cadn.net.cn

例如,假设你有一个视图,用户输入完成酒店预订所需的详细信息,你需要确保登记退房日期遵循一套特定的商业规则。 你可以从过渡元素如下:spring-doc.cadn.net.cn

<view-state id="enterBookingDetails">
	<transition on="proceed" to="reviewBooking">
		<evaluate expression="booking.validateEnterBookingDetails(messageContext)" />
	</transition>
</view-state>

这里,进行事件通过在预订实例上调用模型级验证方法来处理,传递通用的消息上下文实例,以便记录消息。 这些消息随后可以与其他任何JSF消息一起显示在h:信息元件。spring-doc.cadn.net.cn

21.4.4. 处理JSF中的Ajax事件

JSF 内置支持发送 Ajax 请求以及在服务器端执行部分处理和渲染。 你可以通过<f:ajax>facelets 标签。spring-doc.cadn.net.cn

在 Spring Web Flow 中,你还可以选择通过渲染动作指定用于服务器端部分渲染的 ID,具体如下:spring-doc.cadn.net.cn

<view-state id="reviewHotels">
	<on-render>
		<evaluate expression="bookingService.findHotels(searchCriteria)"
					result="viewScope.hotels" result-type="dataModel" />
	</on-render>
	<transition on="next">
		<evaluate expression="searchCriteria.nextPage()" />
		<render fragments="hotels:searchResultsFragment" />
	</transition>
</view-state>

21.5. 在页面上嵌入流程

默认情况下,当流程进入视图状态时,会在渲染视图前执行客户端重定向。 这种方法被称为“POST-REDIRECT-GET”。 它的优点是将一个视图的表单处理与下一个视图的渲染分离。 因此,浏览器的返回和刷新按钮可以无缝使用,不会触发任何浏览器警告。spring-doc.cadn.net.cn

通常,客户端重定向从用户视角是透明的。 然而,在某些情况下,“POST-REDIRECT-GET”可能带来同样的好处。 例如,有时在页面上嵌入一个流程,并用 Ajax 请求驱动,只刷新渲染流程的页面区域,可能会很有用。 在这种情况下,不仅不需要使用客户端重定向,而且这也不是保持页面周围内容完整的理想行为。spring-doc.cadn.net.cn

为了表示流程应以“页面嵌入”模式执行,你可以传递一个额外的流输入属性,称为模式其值为嵌入式.以下示例展示了顶层容器流调用嵌入模式下的子流:spring-doc.cadn.net.cn

<subflow-state id="bookHotel" subflow="booking">
	<input name="mode" value="'embedded'"/>
</subflow-state>

当以“页面嵌入”模式启动时,子流不会在 Ajax 请求期间发出流执行重定向。spring-doc.cadn.net.cn

关于嵌入流的示例,请参见Webflow-Primefaces-Showcase项目。 你可以在本地查看源代码,像构建 Maven 项目一样,然后导入到 Eclipse 或其他 IDE,具体如下:spring-doc.cadn.net.cn

cd some-directory
git clone https://github.com/spring-projects/spring-webflow-samples.git
cd primefaces-showcase
mvn package
# import into Eclipse

你需要查看的具体示例是在“高级Ajax”标签下,名为“带嵌入式子流程的顶层流”。spring-doc.cadn.net.cn

21.6. 同一州的重定向

默认情况下,Web Flow 即使处于相同视图状态,只要当前请求不是 Ajax 请求,也会进行客户端重定向。 这在表单验证失败后非常有用。 如果用户点击刷新或返回,则不会看到任何浏览器警告。 如果Web Flow不做重定向,他们会被引导。spring-doc.cadn.net.cn

这可能导致JSF环境特有的问题,即某个特定的Sun Mojarra监听器组件缓存面孔上下文假设同一实例在整个JSF生命周期中都可用。 然而,在Web Flow中,渲染阶段会暂时暂停,客户端会执行重定向。spring-doc.cadn.net.cn

Web Flow 的默认行为是理想的,JSF 应用不太可能遇到这个问题。 这是因为 Ajax 通常作为 JSF 组件库的默认启用,且 Web Flow 在 Ajax 请求时不会重定向。 不过,如果你遇到这个问题,可以在同一视图内禁用客户端重定向,具体如下:spring-doc.cadn.net.cn

<webflow:flow-executor id="flowExecutor">
	<webflow:flow-execution-attributes>
		<webflow:redirect-in-same-state value="false"/>
	</webflow:flow-execution-attributes>
</webflow:flow-executor>

21.7. 使用JSF处理文件上传

大多数JSF组件提供商都包含某种形式的文件上传组件。 通常,在处理这些组件时,JSF必须完全控制解析多部分请求和Spring MVCMultipartResolver不能使用。spring-doc.cadn.net.cn

Spring Web Flow 已通过 PrimeFaces 的文件上传组件进行了测试。 请查看你 JSF 组件库的文档,了解其他提供商如何配置文件上传。spring-doc.cadn.net.cn

通常,你需要在 Servlet 容器中启用多部分支持, 要么通过在调度器服务web.xml年声明, 或者通过使用jakarta.servlet.MultipartConfigElement在程序化 Servlet 注册中spring-doc.cadn.net.cn

21.8. 使用 Spring Security Facelets 标签库

要使用库,你需要创建一个taglib.xml归档并注册web.xml.spring-doc.cadn.net.cn

你需要创建一个名为/网-INF/springsecurity.taglib.xml内容如下:spring-doc.cadn.net.cn

<?xml version="1.0"?>
<!DOCTYPE facelet-taglib PUBLIC
"-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
"https://java.sun.com/dtd/facelet-taglib_1_0.dtd">
<facelet-taglib>
	<namespace>http://www.springframework.org/security/tags</namespace>
	<tag>
		<tag-name>authorize</tag-name>
		<handler-class>org.springframework.faces.security.FaceletsAuthorizeTagHandler</handler-class>
	</tag>
	<function>
		<function-name>areAllGranted</function-name>
		<function-class>org.springframework.faces.security.FaceletsAuthorizeTagUtils</function-class>
		<function-signature>boolean areAllGranted(java.lang.String)</function-signature>
	</function>
	<function>
		<function-name>areAnyGranted</function-name>
		<function-class>org.springframework.faces.security.FaceletsAuthorizeTagUtils</function-class>
		<function-signature>boolean areAnyGranted(java.lang.String)</function-signature>
	</function>
	<function>
		<function-name>areNotGranted</function-name>
		<function-class>org.springframework.faces.security.FaceletsAuthorizeTagUtils</function-class>
		<function-signature>boolean areNotGranted(java.lang.String)</function-signature>
	</function>
	<function>
		<function-name>isAllowed</function-name>
		<function-class>org.springframework.faces.security.FaceletsAuthorizeTagUtils</function-class>
		<function-signature>boolean isAllowed(java.lang.String, java.lang.String)</function-signature>
	</function>
</facelet-taglib>

接下来,你需要将 taglib 文件(在前面列表中)注册为web.xml如下:spring-doc.cadn.net.cn

<context-param>
	<param-name>jakarta.faces.FACELETS_LIBRARIES</param-name>
	<param-value>/WEB-INF/springsecurity.taglib.xml</param-value>
</context-param>

现在你可以在视图中使用标签库了。 您可以使用授权标签来有条件地包含嵌套内容,具体如下:spring-doc.cadn.net.cn

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:sec="http://www.springframework.org/security/tags">

	<sec:authorize ifAllGranted="ROLE_FOO, ROLE_BAR">
		Lorem ipsum dolor sit amet
	</sec:authorize>

	<sec:authorize ifNotGranted="ROLE_FOO, ROLE_BAR">
		Lorem ipsum dolor sit amet
	</sec:authorize>

	<sec:authorize ifAnyGranted="ROLE_FOO, ROLE_BAR">
		Lorem ipsum dolor sit amet
	</sec:authorize>

</ui:composition>

你也可以在任何JSF组件的渲染或其他属性中使用多个EL函数之一,具体如下:spring-doc.cadn.net.cn

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:sec="http://www.springframework.org/security/tags">

	<!-- Rendered only if user has all of the listed roles -->
	<h:outputText value="Lorem ipsum dolor sit amet" rendered="#{sec:areAllGranted('ROLE_FOO, ROLE_BAR')}"/>

	<!-- Rendered only if user does not have any of the listed roles -->
	<h:outputText value="Lorem ipsum dolor sit amet" rendered="#{sec:areNotGranted('ROLE_FOO, ROLE_BAR')}"/>

	<!-- Rendered only if user has any of the listed roles -->
	<h:outputText value="Lorem ipsum dolor sit amet" rendered="#{sec:areAnyGranted('ROLE_FOO, ROLE_BAR')}"/>

	<!-- Rendered only if user has access to given HTTP method/URL as defined in Spring Security configuration -->
	<h:outputText value="Lorem ipsum dolor sit amet" rendered="#{sec:isAllowed('/secured/foo', 'POST')}"/>

</ui:composition>

21.9. 第三方组件库集成

Spring Web Flow JSF 集成力求与任何第三方 JSF 组件库兼容。 通过在 SWF 驱动的 JSF 生命周期内尊重 JSF 规范的所有标准语义,第三方库一般应该“就能正常工作”。最重要的是,在web.xml略有变化,因为网页流请求不经过标准面圈. 通常,任何传统映射到面圈应映射到Spring调度器服务相反。 (例如,如果你需要逐页迁移遗留的JSF应用,也可以映射到两者。)spring-doc.cadn.net.cn