我在使用Spring Boot和JSF时遇到一些问题。servlet似乎正确启动,但是当我尝试访问资源时,出现以下异常
java.lang.IllegalStateException: Could not find backup for factory javax.faces.context.FacesContextFactory. at javax.faces.FactoryFinder$FactoryManager.getFactory(FactoryFinder.java:1011) at javax.faces.FactoryFinder.getFactory(FactoryFinder.java:343) at javax.faces.webapp.FacesServlet.init(FacesServlet.java:302) at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1284) at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:884) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:134) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501) at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:683) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1720) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1679) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:724)
我的应用程序类如下
@Configuration @EnableAutoConfiguration @ComponentScan public class Application extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(Application.class); } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(Application.class); } @Bean public FacesServlet facesServlet() { return new FacesServlet(); } @Bean public ServletRegistrationBean facesServletRegistration() { ServletRegistrationBean registration = new ServletRegistrationBean( facesServlet(), "*.xhtml"); registration.setName("Christmas"); return registration; } @Bean public ServletListenerRegistrationBean<ConfigureListener> jsfConfigureListener() { return new ServletListenerRegistrationBean<ConfigureListener>( new ConfigureListener()); } }
我没有web.xml或faces-config.xml,而我的pom.xml如下
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.x.y.z</groupId> <artifactId>project</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.1.5.RELEASE</version> </parent> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </dependency> <dependency> <groupId>org.primefaces</groupId> <artifactId>primefaces</artifactId> <version>5.0</version> </dependency> <!-- JSF 2 --> <dependency> <groupId>com.sun.faces</groupId> <artifactId>jsf-api</artifactId> <version>2.1.11</version> </dependency> <dependency> <groupId>com.sun.faces</groupId> <artifactId>jsf-impl</artifactId> <version>2.1.11</version> </dependency> </dependencies> </project>
我怀疑与jsf api有关的依赖项中存在一些冲突,但我似乎无法弄清楚哪里。任何解决此问题的帮助将不胜感激。
要使JSF在不带的Spring Boot上运行,web.xml或者faces- config.xml您需要通过上的init参数强制其加载其配置文件ServletContext。一个简单的方法是实现ServletContextAware:
web.xml
faces- config.xml
ServletContext
ServletContextAware
public class Application implements ServletContextAware { // ... @Override public void setServletContext(ServletContext servletContext) { servletContext.setInitParameter("com.sun.faces.forceLoadConfiguration", Boolean.TRUE.toString()); } }
JSF ConfigureListener还依赖于JSP,因此您需要在pom中添加对Jasper的依赖:
ConfigureListener
<dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> </dependency>
它与您的问题没有直接关系,但是您不需要声明FacesServlet为bean。该ServletRegistrationBean是足够了。
FacesServlet
ServletRegistrationBean
这使得Application.java寻找如下:
Application.java
import javax.faces.webapp.FacesServlet; import javax.servlet.ServletContext; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.context.embedded.ServletListenerRegistrationBean; import org.springframework.boot.context.embedded.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.context.ServletContextAware; import com.sun.faces.config.ConfigureListener; @Configuration @EnableAutoConfiguration @ComponentScan public class Application implements ServletContextAware { public static void main(String[] args) { SpringApplication.run(Application.class); } @Bean public ServletRegistrationBean facesServletRegistration() { ServletRegistrationBean registration = new ServletRegistrationBean( new FacesServlet(), "*.xhtml"); registration.setLoadOnStartup(1); return registration; } @Bean public ServletListenerRegistrationBean<ConfigureListener> jsfConfigureListener() { return new ServletListenerRegistrationBean<ConfigureListener>( new ConfigureListener()); } @Override public void setServletContext(ServletContext servletContext) { servletContext.setInitParameter("com.sun.faces.forceLoadConfiguration", Boolean.TRUE.toString()); } }