Spring Boot JSF 集成

Posted

技术标签:

【中文标题】Spring Boot JSF 集成【英文标题】:Spring Boot JSF Integration 【发布时间】:2018-02-21 14:03:25 【问题描述】:

环境:

雄猫 8

Spring Boot 1.5

JSF 2.2

Apache MyFaces

Spring MVC

代码:

我正在 Servlet 3.0 环境中集成 Spring Boot 和 JSF 2.2。

配置类:

JSFConfig.java - JSF 的配置。

@Configuration
@ComponentScan("com.atul.jsf")
public class JSFConfig 

        @Bean
        public ServletRegistrationBean servletRegistrationBean() 
            FacesServlet servlet = new FacesServlet();
            return new ServletRegistrationBean(servlet, "*.jsf");
        


Spring Boot 主类:

@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);
    

托管 Bean:

UserBean.java - JSF 的托管 Bean

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

小脸:

home.xhtml - 主页

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

中所述
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 是不可发现的

5)我在这里遗漏了什么吗? 6)我没有使用 Spring Boot 提供的嵌入式 tomcat

【问题讨论】:

【参考方案1】:

这就是我让 JSF 使用 Spring Boot 的方式(完整的 sample project at Github, updated with JSF 2.3 and Spring Boot 2):

1.依赖关系

除了标准的 web starter 依赖项之外,您还需要包含标记为已提供的 tomcat 嵌入式 jasper(感谢@Fencer 在here 中的评论)。否则,您将在应用程序启动时遇到异常,因为 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>

2。 Servlet 注册

注册 JSF servlet 并将其配置为在启动时加载(不需要 web.xml)。如果使用 JSF 2.2,最好使用 *.xhtml 映射,至少在使用 facelets 时:

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

让你的配置类实现ServletContextAware,这样你就可以设置你的初始化参数。这里你必须强制 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...

3。 EL 集成

在 faces-config.xml 中声明 EL resolver。这将成为您的视图文件和托管 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>

4.视图范围

编写自定义 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;

5.准备好了!

现在您可以通过以下方式声明您的托管 bean。请记住使用@Autowired(最好在构造函数中)而不是@ManagedProperty,因为您正在处理Spring Beans。

@Component
@Scope("view")
public class MyBean 

    //Ready to go!



仍有待实现

我无法让 JSF 特定的注释在 Spring Boot 上下文中工作。所以@FacesValidator@FacesConverter@FacesComponent等不能用。尽管如此,还是有机会在 faces-config.xml 中声明它们(参见 xsd),这是老式的方式。


另请参阅:

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

【讨论】:

Xtreme Biker 您是否找到了让 JSF 注释工作的方法?也许是 Spring Boot 2.0? 不,但是自从我写了这个答案以来,我还没有挖掘太多。由于是 Spring 在这里管理你的 bean,你可以尝试一些注释生成单例,如 @Component。 @XtremeBiker 真的需要 Jasper 依赖项吗? @John 确实如此。删除它会抛出异常。 该应用程序还依赖于starter-web。该依赖项已经提供了嵌入式 tomcat。这里的问题与嵌入式 tomcat 在编译时不提供 jasper 功能有关,这似乎是 JSF 所要求的。因此,添加该依赖项可以解决它。另见:***.com/a/25777709/1199132

以上是关于Spring Boot JSF 集成的主要内容,如果未能解决你的问题,请参考以下文章

Spring JSF 集成:如何在 JSF 托管 bean 中注入 Spring 组件/服务?

如何在 JSF-Spring 集成应用中启用 CSRF 保护

JSF - Spring 安全集成问题

JSF 与 Spring Security 的集成

我们可以集成 JSF 2.0 + Spring 4.2.X + Spring Security 4.2.X [重复]

Spring Security 4 和 JSF 2 集成