Spring Boot JSF Integration

匿名 (未验证) 提交于 2019-12-03 08:44:33

问题:

Environment :

Tomcat 8

Spring Boot 1.5

JSF 2.2

Apache MyFaces

Spring MVC

Code :

I am integrating Spring Boot and JSF 2.2 in Servlet 3.0 environment.

Config Classes :

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> 

Issue :

1)when I submit form in home.xhtml , userBean.addUser gets called. 2)userBean.name gets set with values entered by user. 3)But userServiceImpl is NULL. 4)Does that mean that Spring and JSF is not getting integrated ? I have also registered SpringBeanFacesELResolver as mentioned in

faces-config.xml  

I also tried removing all JSF specific annotations from UserBean.java and used only Spring specific annotations like below -

 @Component     @SessionScoped      public class UserBean implements Serializable{          /**          *           */         private static final long serialVersionUID = 1L;         private String name;         @Autowired         private UserServiceImpl userServiceImpl;       } 

But when I submit form , I am getting target Unreachable error for #{userBean) . That means userBean is not discoverable for Spring

5)Am I missing anything here ? 6)I am not using embedded tomcat provided with Spring Boot

回答1:

This is the way I have JSF working with Spring Boot:

1. Servlet registration

Register the JSF servlet and configure it to load on startup (no need of web.xml). If working with JSF 2.2, your best is to use *.xhtml mapping, at least when using facelets:

@Bean public ServletRegistrationBean servletRegistrationBean() {     ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(             new FacesServlet(), "*.xhtml");     servletRegistrationBean.setLoadOnStartup(1);     return servletRegistrationBean; } 

Make your configuration class implement ServletContextAware so that you can set your init parameters. Here you must force JSF to load configuration:

@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... } 

2. EL integration

Declare the EL resolver in the faces-config.xml. This is going to be the glue between your view files and your managed bean properties and methods:

<?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> 

3. View Scope

Write a custom Spring scope to emulate the JSF view scope (keep in mind your beans are going to be managed by Spring, not JSF). It should look some way like this:

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;     }  } 

And register it in your configuration class:

@Bean public static CustomScopeConfigurer viewScope() {     CustomScopeConfigurer configurer = new CustomScopeConfigurer();     configurer.setScopes(             new ImmutableMap.Builder<String, Object>().put("view", new ViewScope()).build());     return configurer; } 

4. Ready to go!

Now you can declare your managed beans the way below. Remember to use @Autowired (preferably in constructors) instead of @ManagedProperty, because you're dealing with Spring Beans.

@Component @Scope("view") public class MyBean {      //Ready to go!  } 

Still pending to achieve

I couldn't get JSF specific annotations work in the Spring Boot context. So @FacesValidator, @FacesConverter, @FacesComponent, and so on can't be used. Still, there's the chance to declare them in faces-config.xml (see the xsd), the old-fashioned way.


See also:



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!