Spring Boot JSF Integration

前端 未结 1 946
太阳男子
太阳男子 2020-11-30 11:48

Environment :

Tomcat 8

Spring Boot 1.5

JSF 2.2

Apache MyFaces

Spring MVC

Code :

I am integrating Spring Boot

相关标签:
1条回答
  • 2020-11-30 12:13

    This is the way I have JSF working with Spring Boot (full sample project at Github, updated with JSF 2.3 and Spring Boot 2):

    1. Dependencies

    In addition to the standard web starter dependency, you'll need to include the tomcat embedded jasper marked as provided (thanks @Fencer for commenting in here). Otherwise you'll get an exception at application startup, because of JSF depending on JSP processor (see also the first link at the end of my answer).

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

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

    3. 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>
    

    4. The 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;
    }
    

    5. 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:

    • Spring Boot with JSF; Could not find backup for factory javax.faces.context.FacesContextFactory
    • Porting JSF 2.0’s ViewScope to Spring 3.0
    • JSP file not rendering in Spring Boot web application
    0 讨论(0)
提交回复
热议问题