Environment :
Tomcat 8
Spring Boot 1.5
JSF 2.2
Apache MyFaces
Spring MVC
Code :
我正在Servlet 3.0环境中集成Spring Boot和JSF 2.2。
配置类:
JSFConfig.java - Config for JSF.
@Configuration @ComponentScan({"com.atul.jsf"}) public class JSFConfig { @Bean public ServletRegistrationBean servletRegistrationBean() { FacesServlet servlet = new FacesServlet(); return new ServletRegistrationBean(servlet, "*.jsf"); } }
Spring Boot Main Class :
@SpringBootApplication @Import({ // @formatter:off JPAConfig.class, ServiceConfig.class, // this contains UserServiceImpl.java class. WebConfig.class, JSFConfig.class, }) public class SpringbootJpaApplication extends SpringBootServletInitializer{ public static void main(String[] args) { SpringApplication.run(SpringbootJpaApplication.class, args); } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(SpringbootJpaApplication.class); } }
Managed Bean :
UserBean.java - Managed Bean for JSF
@ManagedBean @SessionScoped public class UserBean implements Serializable{ /** * */ private static final long serialVersionUID = 1L; private String name; @ManagedProperty(value="#{userServiceImpl}") private UserServiceImpl userServiceImpl; public void addUser(){ System.out.println("User Gets added "+this.name); } public String getName() { return name; } public void setName(String name) { this.name = name; } public UserServiceImpl getUserServiceImpl() { return userServiceImpl; } public void setUserServiceImpl(UserServiceImpl userServiceImpl) { this.userServiceImpl = userServiceImpl; } }
Facelets :
home.xhtml - home page
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"> <h:head> <title>JSF 2.0 Hello World</title> </h:head> <h:body> <h2>JSF 2.0 Hello World Example - hello.xhtml</h2> <h:form> <h:inputText value="#{userBean.name}"></h:inputText> <h:commandButton value="Submit" action="#{userBean.addUser}"></h:commandButton> </h:form> </h:body> </html>
faces-config.xml:
<?xml version="1.0" encoding="UTF-8"?> <faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd" version="2.2"> <application> <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver> </application> <lifecycle> <phase-listener>org.springframework.web.jsf.DelegatingPhaseListenerMulticaster</phase-listener> </lifecycle> </faces-config>
问题 :
1)当我提交表格时home.xhtml , userBean.addUser被调用。2)userBean.name设置用户输入的值。3)但是userServiceImpl为NULL。4)这是否意味着Spring和JSF没有集成?我也已经SpringBeanFacesELResolver按照
home.xhtml , userBean.addUser
userBean.name
userServiceImpl
SpringBeanFacesELResolver
faces-config.xml
我还尝试了从UserBean.java中删除所有JSF特定注释,仅使用了Spring特定注释,如下所示-
@Component @SessionScoped public class UserBean implements Serializable{ /** * */ private static final long serialVersionUID = 1L; private String name; @Autowired private UserServiceImpl userServiceImpl; }
但是,当我提交表格时,我遇到了“目标无法到达”错误#{userBean)。这意味着userBean对于Spring是不可发现的
#{userBean)
userBean
5)我在这里想念什么吗?6)我没有使用Spring Boot提供的嵌入式tomcat
除了标准的Web Starter依赖项之外,你还需要包括标记为提供的tomcat嵌入式jasper(感谢@Fencer在此处发表评论)。否则,由于JSF取决于JSP处理器,你将在应用程序启动时遇到异常(另请参见答案末尾的第一个链接)。
<dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
注册JSF Servlet并将其配置为在启动时加载(不需要web.xml)。如果使用JSF 2.2,则最好是*.xhtml至少在使用facelet时使用映射:
@Bean public ServletRegistrationBean servletRegistrationBean() { ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean( new FacesServlet(), "*.xhtml"); servletRegistrationBean.setLoadOnStartup(1); return servletRegistrationBean; }
使你的配置类实现,ServletContextAware以便你可以设置init参数。在这里,你必须强制JSF加载配置:
@Override public void setServletContext(ServletContext servletContext) { servletContext.setInitParameter("com.sun.faces.forceLoadConfiguration", Boolean.TRUE.toString()); servletContext.setInitParameter("javax.faces.FACELETS_SKIP_COMMENTS", "true"); //More parameters... }
在faces-config.xml中声明EL解析器。这将成为视图文件与托管Bean属性和方法之间的粘合剂:
<?xml version="1.0" encoding="UTF-8"?> <faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd" version="2.2"> <application> <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver </el-resolver> </application> </faces-config>
编写一个自定义的Spring范围来模拟JSF视图范围(请注意,你的bean将由Spring而不是JSF管理)。它看起来应该像这样:
public class ViewScope implements Scope { @Override public Object get(String name, ObjectFactory<?> objectFactory) { Map<String, Object> viewMap = FacesContext.getCurrentInstance() .getViewRoot().getViewMap(); if (viewMap.containsKey(name)) { return viewMap.get(name); } else { Object object = objectFactory.getObject(); viewMap.put(name, object); return object; } } @Override public String getConversationId() { return null; } @Override public void registerDestructionCallback(String name, Runnable callback) { } @Override public Object remove(String name) { return FacesContext.getCurrentInstance().getViewRoot().getViewMap().remove(name); } @Override public Object resolveContextualObject(String arg0) { return null; } }
并将其注册到你的配置类中:
@Bean public static CustomScopeConfigurer viewScope() { CustomScopeConfigurer configurer = new CustomScopeConfigurer(); configurer.setScopes( new ImmutableMap.Builder<String, Object>().put("view", new ViewScope()).build()); return configurer; }
现在,你可以按照以下方式声明托管bean。记住要使用@Autowired(最好在构造函数中)代替@ManagedProperty,因为你正在处理Spring Beans。
@Component @Scope("view") public class MyBean { //Ready to go! }
Still pending to achieve
我无法在Spring Boot上下文中使用JSF特定的注释。所以@FacesValidator,@FacesConverter,@FacesComponent,等不能使用。仍然有机会在faces-config.xml中声明它们(参见xsd),这是一种老式的方法。