1. 概述
本文將探討如何從 JSF 管理 Bean 和 JSF 頁面中訪問 Spring 中定義的 Bean,以便將業務邏輯的執行委託給 Spring Bean。
本文假設讀者已對 JSF 和 Spring 獨立了解。本文基於 Mojarra 實現 的 JSF。
2. 在 Spring 中
以下 Bean 在 Spring 中已定義。<em>UserManagementDAO</em> Bean 將用户名添加到內存存儲中,並由以下接口定義:
public interface UserManagementDAO {
boolean createUser(String newUserData);
}使用以下 Java 配置來配置 Bean 的實現:
public class SpringCoreConfig {
@Bean
public UserManagementDAO userManagementDAO() {
return new UserManagementDAOImpl();
}
}或者使用以下 XML 配置:
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
<bean class="com.baeldung.dao.UserManagementDAOImpl" id="userManagementDAO"/>我們通過 XML 定義 Bean,並註冊 CommonAnnotationBeanPostProcessor 以確保 @PostConstruct 註解能夠被識別。
3. 配置
以下部分解釋了用於啓用 Spring 和 JSF 環境集成的配置項。
3.1. 使用 Java 配置而不使用 web.xml
通過實現 WebApplicationInitializer,我們能夠程序化地配置 ServletContext。以下是 MainWebAppInitializer 類中 onStartup() 方法的實現:
public void onStartup(ServletContext sc) throws ServletException {
AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext();
root.register(SpringCoreConfig.class);
sc.addListener(new ContextLoaderListener(root));
}AnnotationConfigWebApplicationContext 啓動 Spring 的上下文,並通過註冊SpringCoreConfig 類添加 Bean。
類似地,在 Mojarra 實現中,有一個FacesInitializer 類,用於配置FacesServlet。要使用此配置,只需擴展FacesInitializer 即可。MainWebAppInitializer 的完整實現如下所示:
public class MainWebAppInitializer extends FacesInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext sc) throws ServletException {
AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext();
root.register(SpringCoreConfig.class);
sc.addListener(new ContextLoaderListener(root));
}
}3.2. 使用 web.xml
我們將首先在應用程序的 web.xml 文件中配置 ContextLoaderListener:
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>這個監聽器負責在 Web 應用程序啓動時啓動 Spring 應用上下文。 默認情況下,它會查找名為 applicationContext.xml 的 Spring 配置文件。
3.3. faces-config.xml
我們現在在 faces-config.xml 文件中配置 SpringBeanFacesELResolver:
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>EL 解決器是 JSF 框架中支持的插件組件,允許我們自定義 JSF 運行時對錶達式語言 (EL) 表達式的評估行為。此 EL 解決器將允許 JSF 運行時通過 JSF 中定義的 EL 表達式訪問 Spring 組件。
4. 通過 JSF 訪問 Spring Bean
到目前為止,我們的 JSF Web 應用程序已經準備好可以從 JSF 後台 bean 或 JSF 頁面訪問我們的 Spring Bean。
<h3><strong>4.1. 從 Backing Bean JSF 2.0 中訪問 Spring Bean</strong></h3>
<p>Spring Bean 現在可以從 JSF Backing Bean 中訪問。根據您運行的 JSF 版本,有以下兩種方法。對於 JSF 2.0,您需要在 JSF 管理 Bean 上使用 <em >@ManagedProperty</em> 註解。</p>
@ManagedBean(name = "registration")
@RequestScoped
public class RegistrationBean implements Serializable {
@ManagedProperty(value = "#{userManagementDAO}")
transient private IUserManagementDAO theUserDao;
private String userName; // getters and setters
}請注意,在使用 @ManagedProperty 時,獲取器和設置器是必選的。 現在 – 為了驗證從管理 Bean 訪問 Spring Bean 的可訪問性,我們將添加 createNewUser() 方法:
public void createNewUser() {
FacesContext context = FacesContext.getCurrentInstance();
boolean operationStatus = userDao.createUser(userName);
context.isValidationFailed();
if (operationStatus) {
operationMessage = "User " + userName + " created";
}
}
該方法的關鍵在於使用 userDao Spring Bean,並訪問其功能。
4.2. 從 JSF 2.2 中的後置Bean
另一種方法,僅在 JSF 2.2 及更高版本中有效,是使用 CDI 的 <em >@Inject</em> 註解。此方法適用於 JSF 管理Bean(帶有 <em >@ManagedBean</em> 註解)和 CDI 管理Bean(帶有 <em >@Named</em> 註解)。
實際上,使用 CDI 註解,這是唯一有效的注入Bean的方法。
@Named( "registration")
@RequestScoped
public class RegistrationBean implements Serializable {
@Inject
UserManagementDAO theUserDao;
}採用這種方法,getter 和 setter 就沒有必要。此外,EL 表達式也不存在。
4.3. 從 JSF 視圖出發
createNewUser() 方法將從以下 JSF 頁面觸發:
<h:form>
<h:panelGrid id="theGrid" columns="3">
<h:outputText value="Username"/>
<h:inputText id="firstName" binding="#{userName}" required="true"
requiredMessage="#{msg['message.valueRequired']}" value="#{registration.userName}"/>
<h:message for="firstName" style="color:red;"/>
<h:commandButton value="#{msg['label.saveButton']}" action="#{registration.createNewUser}"
process="@this"/>
<h:outputText value="#{registration.operationMessage}" style="color:green;"/>
</h:panelGrid>
</h:form>
要渲染頁面,請啓動服務器並導航到:
http://localhost:8080/jsf/index.jsf我們還可以使用 EL 在 JSF 視圖中訪問 Spring Bean。要測試它,只需將之前引入的 JSF 頁面的第 7 行更改為:
<h:commandButton value="Save"
action="#{registration.userDao.createUser(userName.value)}"/>在這裏,我們直接調用 createUser 方法,從 JSF 頁面將 userName 的綁定值傳遞給該方法,從而繞過所有託管 Bean。
5. 結論
我們考察了 Spring 和 JSF 之間的一般集成,在此集成中,我們可以在 JSF bean 和頁面中訪問 Spring bean。
值得注意的是,雖然 JSF 運行時提供了可插拔的架構,從而使 Spring 框架能夠提供集成組件,但 Spring 框架的註解在 JSF 上下文中無法使用,反之亦然。
這意味着您無法在 JSF 管理 bean 中使用諸如 @Autowired 或 @Component 等註解,或者在 Spring 管理 bean 上使用 @ManagedBean 註解。但是,您可以使用 @Inject 註解,既可以在 JSF 2.2+ 管理 bean 中使用,也可以在 Spring bean 中使用(因為 Spring 支持 JSR-330)。