1. 概述
在这篇文章中,我们将探讨如何在JSF(JavaServer Faces)的管理bean和页面中访问Spring定义的bean,以便将业务逻辑的执行委托给Spring bean。本文假设读者已经对JSF和Spring有了一定的理解,文章基于Mojarra实现的JSF。
2. 在Spring中
首先,我们定义一个Spring中的bean,名为UserManagementDAO
,它将在内存存储中添加用户名。该bean由以下接口定义:
public interface UserManagementDAO {
boolean createUser(String newUserData);
}
bean的实现通过以下Java配置进行配置:
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. 不使用web.xml
的Java配置
通过实现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。
4.1. 从JSF 2.0的后端bean
现在可以从JSF后端bean访问Spring bean。根据你运行的JSF版本,有两种可能的方法。在JSF 2.0中,您需要在JSF管理bean上使用@ManagedProperty
注解。
@ManagedBean(name = "registration")
@RequestScoped
public class RegistrationBean implements Serializable {
@ManagedProperty(value = "#{userManagementDAO}")
transient private IUserManagementDAO theUserDao;
private String userName;
// getters and setters
}
请注意,当使用@ManagedProperty
时,getter和setter方法是必需的。现在,为了验证从管理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的@Inject
注解。这适用于带有@ManagedBean
注解的JSF管理bean以及带有@Named
注解的CDI管理bean。
实际上,使用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
我们也可以在JSF视图中使用EL来访问Spring bean。为了测试,只需将之前引入的JSF页面的第7行更改为:
<h:commandButton value="Save"
action="#{registration.userDao.createUser(userName.value)}"/>
在这里,我们在JSF页面内直接调用Spring DAO的createUser
方法,将userName
绑定值传递给方法,完全绕过了管理bean。
5. 总结
我们探讨了Spring和JSF上下文之间的基本集成,使我们能够在JSF的bean和页面中访问Spring bean。
值得注意的是,尽管JSF运行时提供了可插拔架构,使得Spring框架能够提供集成组件,但来自Spring框架的注解(如@Autowired
或@Component
等)不能在JSF上下文中使用,反之亦然。
这意味着你不能在JSF管理bean中使用@Autowired
或@Component
等注解,也不能在Spring管理bean上使用@ManagedBean
注解。然而,你可以在JSF 2.2+的管理bean和Spring bean(因为Spring支持JSR-330)中使用@Inject
注解。
本文所附的源代码可在GitHub获取。