21. JSF 集成

Spring Web Flow 提供了与 JavaServer Faces (JSF) 的集成,使您可以在 Spring Web Flow 控制器中使用 JSF 的 UI 组件模型。 Web Flow 还为 JSF 环境提供了 Spring Security 标签库。 详见 使用 Spring Security Facelets 标签库 以获取更多详细信息。spring-doc.cadn.net.cn

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

21.1. 配置web.xml

第一步是将请求路由到DispatcherServlet文件中的web.xml。 在以下示例中,我们将所有以/spring/开头的URL映射到servlet。 需要对servlet进行配置。 在servlet中使用了init-param来传递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 中配置 FacesServlet,就像通常那样,即使在将 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>

通常,使用 Facelets 而不是 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. 配置 Web Flow 以与 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();
		}
}

主要要点是安装一个管理单个 FacesContextFlowFacesContextLifecycleListener,其在 Web Flow 请求期间有效,并使用来自 faces 自定义命名空间的 flow-builder-services 元素来为 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>

resources 自定义命名空间元素将 JSF 资源请求委托给 JSF 资源 API。 JsfFlowHandlerAdapter 是通常与 Web Flow 一起使用的 FlowHandlerAdapter 的替代品。 此适配器使用 JsfAjaxHandler 而不是 SpringJavaScriptAjaxHandler 来初始化自身。spring-doc.cadn.net.cn

当您使用 Java 配置时,AbstractFacesFlowConfiguration 基类会自动注册 JsfResourceRequestHandler,因此无需进一步操作。spring-doc.cadn.net.cn

21.3. 替换 JSF 托管 Bean 功能

当您将 JSF 与 Spring Web Flow 结合使用时,可以完全用 Web Flow 管理的变量和 Spring 管理的 Bean 的组合来替代 JSF 管理的 Bean 功能。 它让您对托管对象的生命周期拥有更强的控制能力,并为领域模型的初始化和执行提供了定义明确的钩子。 此外,由于您很可能已经在业务层使用了 Spring,因此减少了维护两种不同托管 Bean 模型的概念性负担。spring-doc.cadn.net.cn

如果仅进行纯 JSF 开发,您可能会很快发现,请求范围的生命周期不足以存储驱动复杂事件驱动视图的会话模型对象。 在 JSF 中,通常的做法是将内容放入会话范围,但这带来了在进入另一个视图或应用程序功能区域之前清理这些对象的额外负担。 真正需要的是一种介于请求范围和会话范围之间的托管范围。 JSF 提供了 flash 和 view 范围,可以通过 UIViewRoot.getViewMap() 以编程方式访问。 Spring Web Flow 提供了对 flash、view、flow 和 conversation 范围的访问。 这些范围通过 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 bean 一样,所有可用的作用域都会被搜索以找到匹配的变量,因此您可以在流程定义中更改变量的作用域,而无需修改引用它的 EL 表达式。spring-doc.cadn.net.cn

您还可以定义作用域为当前视图的视图实例变量,这些变量在切换到另一个视图时会自动清理。 这在使用 JSF 时非常有用,因为视图通常会被构造为在多次请求中处理页面内的多个事件,然后才会切换到另一个视图。spring-doc.cadn.net.cn

要定义视图实例变量,可以在view-state定义中使用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 Beans

尽管定义自动装配的流程实例变量提供了良好的模块化和可读性,但有时您可能希望使用 Spring 容器的其他功能,例如面向切面编程 (AOP)。 在这些情况下,您可以在 Spring 的 ApplicationContext 中定义一个 bean,并为其指定特定的 Web 流作用域,如下所示:spring-doc.cadn.net.cn

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

这种方法的主要区别在于,bean 在通过 EL 表达式首次访问之前不会完全初始化。 这种通过 EL 实现的延迟实例化与 JSF 托管 bean 的典型分配方式非常相似。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 DataModel中,以便可以在标准的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" 导致使用自定义 List<Booking> 类型包装 DataModel。 自定义 DataModel 提供了额外的便利,例如可序列化以便在请求范围之外存储,以及在 EL 表达式中访问当前选中的行。 例如,在从某个视图回发时,如果动作事件是由 DataTable 内的组件触发的,则可以对所选行的模型实例执行操作,如下所示:spring-doc.cadn.net.cn

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

Spring Web Flow 提供了两种自定义的 DataModel 类型:OneSelectionTrackingListDataModelManySelectionTrackingListDataModel。 从名称可以看出,它们分别用于跟踪一个或多个选中的行。 这是通过 SelectionTrackingActionListener 监听器实现的,该监听器响应 JSF 操作事件,并调用 SelectionAware 数据模型上的适当方法来记录当前点击的行。spring-doc.cadn.net.cn

要理解这是如何配置的,请记住,FacesConversionService 在启动时会针对别名 dataModel 注册一个 DataModelConverter。 当在流定义中使用 result-type="dataModel" 时,它会导致使用 DataModelConverter。 然后转换器将给定的 ListOneSelectionTrackingListDataModel 的实例包装起来。 要使用 ManySelectionTrackingListDataModel,你需要注册自己的自定义转换器。spring-doc.cadn.net.cn

21.4. 使用 Spring Web Flow 处理 JSF 事件

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

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

JSF 中一个简单但常见的场景是需要发出一个事件,该事件以某种方式对模型进行操作,然后重新显示相同的视图以反映模型状态的变化。 流程定义语言在 transition 元素中对此提供了特殊支持。spring-doc.cadn.net.cn

一个很好的例子是分页列表结果的表格。 假设您希望仅加载和显示大型结果列表的一部分,并让用户逐步翻阅结果。 初始的 view-state 定义以加载和显示列表如下所示: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 DataTable来显示当前的hotels列表,然后在表格下方放置一个More Results链接,如下所示:spring-doc.cadn.net.cn

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

commandLink 从其 next 属性发出一个 action 事件。 然后,您可以通过添加到 view-state 定义来处理该事件,如下所示: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>

在这里,你通过增加searchCriteria实例的页数来处理next事件。 然后使用更新后的条件再次调用on-render操作,这会导致下一页结果被加载到DataModel中。 由于transition元素上没有to属性,因此会重新渲染相同的视图,并且模型中的更改会反映在视图中。spring-doc.cadn.net.cn

21.4.2. 处理 JSF 操作事件

超越页面内事件的下一个逻辑层面是需要导航到另一个视图的事件,期间会对模型进行一些操作。 使用纯 JSF 实现这一点需要在 faces-config.xml 中添加导航规则,并且可能需要在 JSF 托管 Bean 中编写一些中间 Java 代码(这两项任务都需要重新部署)。而使用流定义语言,您可以像处理页面内事件那样,以简洁的方式在一个地方处理这种情况。spring-doc.cadn.net.cn

继续我们对分页结果列表进行操作的用例,假设我们希望显示的 DataTable 中的每一行都包含一个指向该行实例详细信息页面的链接。 您可以向表格中添加一列,其中包含以下 commandLink 组件,如下所示:spring-doc.cadn.net.cn

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

这将引发 select 事件,然后你可以通过向现有的 view-state 添加另一个 transition 元素来处理它,如下所示: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>

在这里,select 事件通过将当前选中的酒店实例从 DataTable 推送到流程范围中进行处理,以便 reviewHotel view-state 可以引用它。spring-doc.cadn.net.cn

21.4.3. 执行模型验证

JSF 提供了在更改应用于模型之前在字段级别验证输入的有用功能。 然而,当您需要在更新应用之后再执行更复杂的模型级别验证时,通常只能通过在托管 Bean 的 JSF 操作方法中添加更多自定义代码来实现。 这种类型的验证通常是领域模型本身的职责,但如果不引入对 JSF API 的不必要依赖,很难将任何错误消息传播回视图层。spring-doc.cadn.net.cn

使用 Web Flow 时,您可以在业务代码中使用通用且低级别的 MessageContext,并在其中添加的任何消息在渲染时都可以供 FacesContext 使用。spring-doc.cadn.net.cn

例如,假设您有一个视图,用户可以在其中输入完成酒店预订所需的详细信息,并且您需要确保Check InCheck Out日期符合一组给定的业务规则。 您可以从transition元素中调用这种模型级别的验证,如下所示:spring-doc.cadn.net.cn

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

在这里,通过调用预订实例上的模型级验证方法来处理 proceed 事件,传递通用的 MessageContext 实例,以便记录消息。 然后,这些消息可以与 h:messages 组件中的其他 JSF 消息一起显示。spring-doc.cadn.net.cn

21.4.4. 处理 JSF 中的 Ajax 事件

JSF 提供了对发送 Ajax 请求以及在服务器端执行部分处理和渲染的内置支持。 您可以通过 <f:ajax> facelets 标签指定部分渲染的 ID 列表。spring-doc.cadn.net.cn

在 Spring Web Flow 中,您还可以选择使用 render 操作指定服务器端用于部分渲染的 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”(Post 转向 Get)。 它的优点是将一个视图的表单处理与下一个视图的渲染分离开来。 因此,浏览器的后退和刷新按钮可以无缝工作,而不会引发任何浏览器警告。spring-doc.cadn.net.cn

通常,客户端重定向从用户的角度来看是透明的。 然而,在某些情况下,“POST-REDIRECT-GET”可能不会带来相同的好处。 例如,有时将流程嵌入到页面中并通过Ajax请求来驱动它可能是有用的,这样可以仅刷新页面中渲染流程的区域。 在这种情况下,不仅没有必要使用客户端重定向,而且就保持页面周围内容的完整性而言,这也不是期望的行为。spring-doc.cadn.net.cn

为了指示流程应以“页面嵌入”模式执行,您可以传递一个名为 mode 的额外流程输入属性,并将其值设置为 embedded。以下示例展示了一个顶级容器流程以嵌入模式调用子流程的情况: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 监听器组件缓存了 FacesContext,并假设在整个 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 MVC的MultipartResolverspring-doc.cadn.net.cn

Spring Web Flow 已经测试了来自 PrimeFaces 的文件上传组件。 检查您的 JSF 组件库的文档,了解其他提供商如何配置文件上传。spring-doc.cadn.net.cn

通常,您需要在 Servlet 容器中启用多部分支持, 要么通过在 web.xml 中的 DispatcherServlet 声明添加一个 \"multipart-config\" 元素, 要么通过在程序化 servlet 注册中使用 jakarta.servlet.MultipartConfigElementspring-doc.cadn.net.cn

21.8. 使用 Spring Security Facelets 标签库

要使用该库,您需要创建一个 taglib.xml 文件并将其注册到 web.xml 中。spring-doc.cadn.net.cn

你需要创建一个名为 /WEB-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>

接下来,您需要在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>

现在你已经可以在视图中使用标签库了。 你可以使用authorize标签有条件地包含嵌套内容,如下所示: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 组件的 rendered 或其他属性中使用多个 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 中的配置会略有变化,因为 Web Flow 请求不会通过标准的 FacesServlet 路由。通常,传统上映射到 FacesServlet 的任何内容都应该改为映射到 Spring 的 DispatcherServlet。(如果需要逐页迁移传统的 JSF 应用程序页面,也可以同时映射到两者。)spring-doc.cadn.net.cn