—— Spring Boot可以支持构建很多类型的应用程序,而不仅仅是微服务。 让我们用Spring Boot构建一个JSF应用程序。

原文:https://auth0.com/blog/developing-jsf-applications-with-spring-boot/

Bruno Krebs  May 09, 2017

Spring Boot最初是应用于微服务相关应用程序,但是,由于它是基于Spring框架的,所以许多人开始想知道如何将JavaServer Faces(JSF)与Spring Boot集成。 在本文中,我们将把这些组合在一起,构建一个小应用程序,使用户能够将“产品信息”列出并保存到数据库中。

JSF是什么?

JavaServer Faces(JSF)是一种Java规范,它提供了一种以组件为中心的用户界面(UI)构建方法(从而简化了Java服务器端应用程序的开发。) JSF上的视图是通过称为视图模板的XML文件来描述的,通常依赖于服务器端会话来存储UI组件的状态。 例如,假设我们想要显示一个HTML“产品”表。 为此,我们需要一个包含以下内容的XML文件:

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
<ui:composition template="base-layout.xhtml">
    <ui:define name="content">
        <h:form id="form">
            <h:dataTable id="table" var="product" value="#{productListController.products}">
                <h:column>
                    <f:facet name="header">Name</f:facet>
                    <h:outputText value="#{product.name}" />
                </h:column>
                <h:column>
                    <f:facet name="header">Action</f:facet>
                    <h:commandButton id="delete" action="#{productListController.delete(product)}" label="Delete" />
                </h:column>
            </h:dataTable>
        </h:form>
</ui:define>
</ui:composition>
</html>

在这种情况下,视图将通过使用h:dataTable组件在一个名为productListController的支持bean的帮助下进行呈现,该bean将为请求者生成HTML响应。 在呈现网页之后,JSF将保留服务器端的视图状态,以允许后续的交互。

JSF与SpringBoot的集成

首先,我们将fork或clone为本文专门创建的GitHub repo(https://github.com/auth0-blog/spring-boot-faces)。我们也可以使用Spring Initilizr网页(https://start.spring.io/),它简单直观。但是,由于我们要构建的应用程序将具有一些其他依赖项(如HSQLDB和Flyway),从fork开始会更容易。

JSF依赖项(基于Maven)

在派生存储库之后,打开您喜欢的IDE (Eclipse、IntelliJ IDEA、Netbeans等),并将初始项目作为Maven项目导入。在IDE上正确导入应用程序后,我们要做的第一件事是添加一些依赖项。让我们打开pom,添加嵌套在<dependecies></dependecies>元素中的以下元素:

        <dependency>
			<groupId>org.apache.myfaces.core</groupId>
			<artifactId>myfaces-impl</artifactId>
			<version>2.2.12</version>
		</dependency>
		<dependency>
			<groupId>org.apache.myfaces.core</groupId>
			<artifactId>myfaces-api</artifactId>
			<version>2.2.12</version>
		</dependency>
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-jasper</artifactId>
		</dependency>
		<dependency>
			<groupId>org.ocpsoft.rewrite</groupId>
			<artifactId>rewrite-servlet</artifactId>
			<version>3.4.1.Final</version>
		</dependency>
		<dependency>
			<groupId>org.ocpsoft.rewrite</groupId>
			<artifactId>rewrite-integration-faces</artifactId>
			<version>3.4.1.Final</version>
		</dependency>
		<dependency>
			<groupId>org.ocpsoft.rewrite</groupId>
			<artifactId>rewrite-config-prettyfaces</artifactId>
			<version>3.4.1.Final</version>
		</dependency>
		<dependency>
			<groupId>org.primefaces</groupId>
			<artifactId>primefaces</artifactId>
			<version>6.1</version>
		</dependency>

从上到下,让我们揭开这些依赖关系的神秘面纱。 前两个依赖项myfaces-api和myfaces-impl是JSF接口规范(-api)和实现(-impl)。 需要第三个依赖项tomcat-embed-jasper,以便JVM可以在运行时解析并执行JSF视图。

之后,org.ocpsoft.rewrite作为groupId的值有三个依赖项。 这些依赖项与Rewrite相关,Rewrite是一种面向Servlet和Java Web框架的开源路由和URL重写解决方案。 使用JSF而不使用像Rewrite这样的工具会导致我们使用丑陋且非RESTful友好的URL,这URL大量使用查询参数进行导航。 因此,我们将使用Rewrite来实现直观,收藏和漂亮的URL。

添加的最后一个依赖项primefaces是一个JSF的开源UI框架,它包含一百多个组件,如数据表,拖放,叠加对话框等。这个框架将帮助我们轻松创建漂亮的用户界面。

现在,让我们打开pom.xml文件,通过向其添加以下行来更改构建过程:

<build>
  <outputDirectory>src/main/webapp/WEB-INF/classes</outputDirectory>
  <!-- plugins... -->
</build> 

这种配置很重要,因为Rewrite不准备在非经典Web应用程序上扫描配置(即在Spring Boot等嵌入式应用程序上)。 所以我们需要稍微调整构建过程,以帮助Rewrite实现它的目标。

JSF配置

接下来,我们将创建两个XML文件。 第一个是web.xml,经验丰富的Java Web开发人员对它已经滚瓜烂熟了。 在常规的Spring Boot应用程序中,我们不需要此文件。 但是,由于我们将使用JSF,我们需要配置FacesServlet servlet和几个listener。 让我们在名为src / main / webapp / WEB-INF /的新目录下创建此文件,并添加以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="3.1">
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.jsf</url-pattern>
    </servlet-mapping>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>
</web-app>

此文件中的前两个元素负责设置FacesServlet并对其进行配置。 servlet-mapping元素指示此servlet处理对* .jsf URL的请求,并在JSF的上下文中处理它们。 最后两个元素,listener元素,负责将JSF集成到Spring上下文中。

我们需要的第二个XML文件是faces-config.xml。 让我们在src / main / webapp / WEB-INF /文件夹下创建这个文件,其中包含以下内容:

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

这个文件所做的就是注册一个ELResolver(即表达式语言解析器),它将解析名称引用的责任委托给Spring的WebApplicationContext上下文。有了它,我们可以在JSF上下文中使用Spring托管bean。

最后一步,我们需要更新项目的Application类以创建另外两个bean。 这是通过如下配置此类来完成的:

package com.auth0.samples.bootfaces;
import org.ocpsoft.rewrite.servlet.RewriteFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import javax.faces.webapp.FacesServlet;
import javax.servlet.DispatcherType;
import java.util.EnumSet;

@EnableAutoConfiguration
@ComponentScan({"com.auth0.samples.bootfaces"})
public class Application extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

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

    @Bean
    public FilterRegistrationBean rewriteFilter() {
        FilterRegistrationBean rwFilter = new FilterRegistrationBean(new RewriteFilter());
        rwFilter.setDispatcherTypes(EnumSet.of(DispatcherType.FORWARD, DispatcherType.REQUEST,
                DispatcherType.ASYNC, DispatcherType.ERROR));
        rwFilter.addUrlPatterns("/*");
        return rwFilter;
    }
}

创建了两个XML文件,正确导入了依赖项,并配置了Application类,我们已准备好开始在Spring Boot上开发JSF应用程序。

基于github工程的构建和配置(译者补充)

如果基于github工程fork出来,或者clone,使用eclipse导入会报错,可以通过以下方式进行解决。

问题一:转换成一个Maven工程

通过右键点击工程,选中“Configure”中的“Convert to Maven Project”,进行Maven工程转换。

 

构建成功以后,工程就会变成如下所示:

  1. src/main/java这样的目录就变成了Source Folder,而原来只是一个普通的文件目录。
  2. 出现JRE System Library
  3. 出现Maven Dependencies

解决错误

转换成Maven工程后,会出现一些错误,如图:

针对报错的是三个,在操作系统中添加对应的目录:

src/test/java

target/generated-sources/annotations

target/generated-test-sources/test-annotations

然后,刷新工程,错误就会消失。

包名无法识别

有可能会出现包名无法识别的异常,明明就在这个包下,但是报错:

解决方式:先把该类移到新包下,再重构包名,修改回来即可。

 

(未完待续)

用SpringBoot开发JSF应用程序系列文章:

用SpringBoot开发JSF应用程序(一)

用SpringBoot开发JSF应用程序(二)

用SpringBoot开发JSF应用程序(三)

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐