Spring Boot 2.7.1 与 JSF 2.2 (Mojarra) 和 Primefaces 6.2.9 集成

2023-11-30

我已经使用下面的堆栈进行了工作设置 -

春季MVC 5
JSF Mojarra 2.2.14
Primefaces 6.2.9

  • 该应用程序是作为 WAR 构建的。
  • 它具有配置了 FacesServlet 的 web.xml 来服务 *.xhtml 请求。 JSF 和 Primefaces 的所有初始化参数都定义为 web.xml 中的上下文参数。
  • 它还具有定义了 SpringBeanFacesELResolver 的 faces-config.xml。
  • @javax.faces.bean.ManagedBean 与 @ManagedProperty 和 JSF 作用域一起用于所有 JSF Managed Bean。托管 Bean 使用 @managementproperty 获取对 Spring beans 的引用,并进行服务调用以填充要在 JSF XHTML 页面中显示的数据。
  • @ManagedBean 类也使用 @PostConstruct 进行初始化。

这在 weblogic 应用服务器和 tomcat 中都运行良好。

我们正在尝试使用最新的 2.7.1 版本将其转换为 Spring boot 项目。作为本次活动的一部分

  • web.xml 已替换为 java 配置类,如下所示 -
@SpringBootApplication(scanBasePackages = {"com.demo.spring.boot.jsfprimefaces","com.xxx.eee"})
@ImportResource({"classpath:spring-root-config.xml","classpath:spring-security-config.xml","classpath:spring-restclient-config.xml"})
public class JsfPrimefacesApplication implements ServletContextInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        servletContext.setInitParameter("com.sun.faces.forceLoadConfiguration", Boolean.TRUE.toString()); 
        // Set JSF/Primefaces init params
        servletContext.setInitParameter("javax.faces.DEFAULT_SUFFIX", ".xhtml");
        servletContext.setInitParameter("javax.faces.STATE_SAVING_METHOD", "client");
        servletContext.setInitParameter("javax.faces.PROJECT_STAGE", "Production");
        servletContext.setInitParameter("javax.faces.VALIDATE_EMPTY_FIELDS", "false");
        servletContext.setInitParameter("javax.faces.FACELETS_SKIP_COMMENTS", "true");
        //servletContext.setInitParameter("javax.faces.CONFIG_FILES", "/WEB-INF/faces-config.xml");
        servletContext.setInitParameter("javax.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE", "true");

        servletContext.setInitParameter("primefaces.THEME", "aristo");
        servletContext.setInitParameter("primefaces.PUBLIC_CAPTCHA_KEY", "DDDDD");
        servletContext.setInitParameter("primefaces.PRIVATE_CAPTCHA_KEY", "EEEEE");
        servletContext.setInitParameter("primefaces.UPLOADER", "commons");

        FacesInitializer facesInitializer = new FacesInitializer();
        facesInitializer.onStartup(null, servletContext);

    }

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

}

很少有其他 @Configuration 类 -

@Configuration
public class PortalFilterConfiguration {

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

    @Bean
    public ServletListenerRegistrationBean<JsfApplicationObjectConfigureListener> jsfConfigureListener() {
        return new ServletListenerRegistrationBean<JsfApplicationObjectConfigureListener>(
                new JsfApplicationObjectConfigureListener());
    }

    static class JsfApplicationObjectConfigureListener extends ConfigureListener {

        @Override
        public void contextInitialized(ServletContextEvent sce) {
            super.contextInitialized(sce);

            ApplicationFactory factory = (ApplicationFactory) FactoryFinder
                    .getFactory(FactoryFinder.APPLICATION_FACTORY);
            Application app = factory.getApplication();

            app.addELResolver(new SpringBeanFacesELResolver());
        }
    }

}
@Configuration
public class PortalServletConfiguration {

    @Bean
    public ServletRegistrationBean<FacesServlet> jsfServletRegistration(ServletContext servletContext) {
        ServletRegistrationBean<FacesServlet> srb = new ServletRegistrationBean<FacesServlet>();
        srb.setServlet(new FacesServlet());
        srb.setUrlMappings(Arrays.asList("*.xhtml"));
        srb.setLoadOnStartup(1);
        return srb;
    }
}

以下是 pom.xml 内容 -

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.1</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.demo.spring.boot</groupId>
    <artifactId>jsf-primefaces</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>jsf-primefaces</name>
    <description>Demo project for Spring Boot JSF Primefaces</description>
    <packaging>war</packaging>
    <repositories>
        <repository>
            <id>no-commons-logging</id>
            <name>No-commons-logging Maven Repository</name>
            <layout>default</layout>
            <url>http://repository.jboss.org/</url>
        </repository>
        <repository>
            <id>prime-repo</id>
            <name>Prime Repo</name>
            <url>http://repository.primefaces.org</url>
        </repository>
        <repository>
            <id>localrepository</id>
            <url>file://../3rd-Party-Dependencies</url>
        </repository>
    </repositories>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-ldap</artifactId>
        </dependency>
        <dependency>
            <groupId>com.oracle.database.jdbc</groupId>
            <artifactId>ojdbc8</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!-- JSF Libraries -->
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>2.2.14</version>
        </dependency>
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-impl</artifactId>
            <version>2.2.14</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>
        <!-- Primefaces & its dependent jars -->
        <dependency>
            <groupId>org.primefaces</groupId>
            <artifactId>primefaces</artifactId>
            <version>6.2.9</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-config-prettyfaces</artifactId>
            <version>3.4.1.Final</version>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>18.0</version>
        </dependency>   
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <dependency>
                <groupId>net.sf.opencsv</groupId>
                <artifactId>opencsv</artifactId>
                <version>2.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox</artifactId>
            <version>2.0.24</version>
        </dependency>           
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <outputDirectory>src/main/webapp/WEB-INF/classes</outputDirectory>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

faces-config.xml 放置在 src/main/webapp/WEB-INF 下。内容如下——

<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>
<locale-config>.....
<resource-bundle>.....
 </application>
</faces-config>

ISSUE

应用程序启动正常。但似乎没有一个 JSF 托管 bean 被初始化,因为我根本没有看到 @PostContruct 方法被调用。所有使用托管 bean 名称的 EL 引用(例如 #{})都会失败,并出现以下错误:

javax.faces.view.facelets.TagAttributeException Attribute did not evaluate to a String or Locale: null

当我在 @ManagedBean 之上添加 @Component 到 JSF 托管 bean 之一时,这会导致调用 @PostConstruct ,这可能意味着在我们的旧设置中,@ManagedBean 类由 JSF 加载,但在这个新设置中,它们会得到被忽略。

任何人都可以帮忙建议需要做什么才能使这项工作成功吗?

Regards
Jacob

UPDATE 1
根据评论,修改了配置类如下 -

@SpringBootApplication(scanBasePackages = { "com.demo.spring.boot.jsfprimefaces", "com.ddd.efulfillment" })
@ImportResource({ "classpath:spring-root-config.xml", "classpath:spring-security-config.xml",
        "classpath:spring-restclient-config.xml" })
public class JsfPrimefacesApplication extends SpringBootServletInitializer {

    @Bean
    public ServletContextInitializer servletContextInitializer() {
        return servletContext -> {
            //servletContext.addListener(com.sun.faces.config.ConfigureListener.class);
            servletContext.setInitParameter("com.sun.faces.forceLoadConfiguration", Boolean.TRUE.toString());
            // Set JSF/Primefaces init params
            servletContext.setInitParameter("javax.faces.DEFAULT_SUFFIX", ".xhtml");
            servletContext.setInitParameter("javax.faces.STATE_SAVING_METHOD", "client");
            servletContext.setInitParameter("javax.faces.PROJECT_STAGE", "Production");
            servletContext.setInitParameter("javax.faces.VALIDATE_EMPTY_FIELDS", "false");
            servletContext.setInitParameter("javax.faces.FACELETS_SKIP_COMMENTS", "true");
            // servletContext.setInitParameter("javax.faces.CONFIG_FILES",
            // "/WEB-INF/faces-config.xml");
            servletContext.setInitParameter("javax.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE",
                    "true");

            servletContext.setInitParameter("primefaces.THEME", "aristo");
            servletContext.setInitParameter("primefaces.PUBLIC_CAPTCHA_KEY",
                    "ddd");
            servletContext.setInitParameter("primefaces.PRIVATE_CAPTCHA_KEY",
                    "ssss");
            servletContext.setInitParameter("primefaces.UPLOADER", "commons");
            FacesInitializer facesInitializer = new FacesInitializer();
            facesInitializer.onStartup(null, servletContext);

        };
    }

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

但仍然存在同样的问题。

在调试时,似乎托管 bean 通过方法“processAnnotations(ManagedBean.class);”在 com.sun.faces.config.processor.ManagedBeanConfigProcessor 类中标识。它有类似于下面的代码

 FacesContext ctx = FacesContext.getCurrentInstance();
        ApplicationAssociate associate =
              ApplicationAssociate.getInstance(ctx.getExternalContext());
        AnnotationManager manager = associate.getAnnotationManager();
        manager.applyConfigAnnotations(ctx,
                                      annotationType,
                                      ConfigManager.getAnnotatedClasses(ctx).get(annotationType));

我认为 @ManagedBean 注释类的 MAP 为 NULL。不知道为什么。


只有在将具有这些注释的类显式提供给 FacesInitializer 后,JSF 2.2 注释才会被识别,如下所示 -

facesInitializer.onStartup(loadJSFAnnotatedClasses(package1...packageN),servletContext);

import com.google.common.collect.ImmutableMap;
import com.google.common.reflect.ClassPath;

private Set<Class<?>> loadJSFAnnotatedClasses(String... packageNames) {
        Set<Class<?>> annotatedClasses = new HashSet<Class<?>>();
        try {
            for (String packageName : packageNames) {
                annotatedClasses.addAll(ClassPath.from(ClassLoader.getSystemClassLoader()).getAllClasses().stream()
                        .filter(clazz -> clazz.getPackageName().equalsIgnoreCase(packageName))
                        .map(clazz -> clazz.load()).collect(Collectors.toSet()));
            }
        } catch (Exception e) {
            return annotatedClasses;
        }

        return annotatedClasses;
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring Boot 2.7.1 与 JSF 2.2 (Mojarra) 和 Primefaces 6.2.9 集成 的相关文章

随机推荐

  • 如何编译wxsqlite3和sqlite以获得加密支持

    我正在开发一个基于 wxWidgets 的 C 项目 使用wxSqlite3访问sqlite数据库 并且工作正常 但我想为数据库添加一些加密 在这里我通过 wxSqlite3 访问加密数据库时遇到问题 据我所知 sqlite默认不支持加密
  • Ansible 使用了错误版本的 Python

    我已经处理这个问题几天了 我在树莓派上运行ansible 我已将Python3 7设为Python的默认版本 显然 Ansible 希望使用 Python 2 7 我已在 playbook 的 vars 中添加了版本 3 7 但这不会更改模
  • 在全屏 Win32 OpenGL 中处理最小化

    我正在尝试使用 Win32 和 OpenGL 创建一个全屏应用程序 我使用更改分辨率EnumDisplaySettings and ChangeDisplaySettings并且 OpenGL 功能运行良好 在其 WndProc 上 我处理
  • Swing 中的进度对话框

    我怎样才能制作模态JDialog没有按钮出现的持续时间需要Runnable实例完成并让该实例更新该对话框上的进度条 消息 显然意大利面条代码可能有效 但我正在寻找一种干净的设计 如果存在 您可能想调查一下进度监视器 如果操作时间较长 会自动
  • .Net 控制计算机之间大小的变化

    我有一个奇怪的问题 我需要弄清楚如何解决 过去几周我一直在我的笔记本电脑上开发一个项目 但是当我在其中一台工作电脑上打开程序时 很多控件的尺寸错误和重叠等 机器之间的差异是这样的 Laptop Windows 7 专业版 显示 1920 1
  • 在MySQL中,我们如何判断表的索引是否是聚集索引?

    在MySQL中 我们如何判断表的索引是否是聚集索引 我们可以用show index from table name获取有关表索引的信息 但我没有发现它显示每个索引是聚集的还是非聚集的 这样做的目的是MySQL中如果一个表有索引 那么该表就必
  • Django FormWizard 动态改变 form_list

    我在使用表单向导时遇到了一些问题 也许有人可以解释一下 根据 process step 方法中的文档字符串 我可以 动态更改 self form list 因此 根据我的项目需求 我将表单附加到 form list 中 我附加的表格包含问题
  • 在外发电子邮件 EWS 中设置回复地址

    运行交换 2013 我在 C 服务中使用 EWS 该服务从服务帐户发送电子邮件 我想让电子邮件有一个与发送帐户不同的回复地址 即通讯组列表地址 我怎样才能做到这一点 这EmailMessage ReplyTo字段是只读的 Code Exch
  • Django 快捷方式嵌套外键

    假设我的 models py 中有以下内容 class Book pass class Part book models ForeignKey Book class Chapter part models ForeignKey Part n
  • 它不会创建 Java VM (JNI)

    我的简单命令行应用程序 int tmain int argc TCHAR argv JavaVM jvm JNIEnv env JavaVMInitArgs vm args JavaVMOption options 1 options 0
  • 扩展server_name(SNI扩展)不与jdk1.8.0一起发送,但与jdk1.7.0一起发送

    我已经使用 ApacheCXF v3 0 4 实现了 JAX WS 客户端 一切正常 但当我想使用 java 8 jdk1 8 0 25 的安全连接 SSL TLS 时 问题就出现了 我在日志中看到以下异常 Djavax net debug
  • 如何在未知输入类型下使用 cin?

    我有一个 C 程序 需要接受用户输入 用户输入要么是两个整数 例如 1 3 要么是一个字符 例如 s 我知道我可以像这样得到两个整数 cin gt gt x gt gt y 但是 如果输入的是 char 我该如何获取 cin 的值呢 我知道
  • 在 IIS Express 中配置最大请求数

    如何配置 IIS Express 中允许的最大请求数 我想将其更改为仅允许一些请求来测试超出限制时会发生什么 可以使用以下方式配置 IIS ExpressapplicationHost config文件 它位于 userprofile my
  • Java - 如何将 PDF 打印到特定打印机?

    我在 Windows 8 1 中有 5 台打印机 并且 PDF 文件不在本地系统中 而是在 PHP 服务器中生成的 问题 如何从服务器获取 PDF 文件并打印到特定打印机 我正在尝试使用 Apache PDFBox 2 0 0 EDIT i
  • 如何分解行? [复制]

    这个问题在这里已经有答案了 我有一个数据表 如下所示 cep3 lt structure list lat c 23 39429 23 39988 23 38233 23 39009 23 40135 23 4019 lon c 46 32
  • 替换 tel 或 telprompt 拨打电话

    我制作了一个应用程序 用于在按下按钮时呼叫预定义的号码 据我所知 在应用程序内拨打电话的唯一方法是使用 tel 或 telprompt 当我提交应用程序时 我收到了带有以下描述的拒绝 2 5 详情 您的应用程序使用或引用以下非公共 API
  • php中事件的含义

    我也知道php和nodejs 在javascript中我们有异步编程 所以我理解其中事件的含义 但是我看到了Yii 和 Zend 2 中的事件也使用它们 但我无法理解它的含义 它在 php 中如何工作以及它到底有什么作用 首先 PHP中没有
  • 如何读取Android设备上的CPU频率[关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 目前不接受答案 有没有 Java API 可以实现这一点 我怎样才能阅读这些信息 要在 Android 上获得频率 只需读取 sys 目录中的这些特殊文件 cat
  • 根据另一个日期选择器实例更改 jQuery 日期选择器中显示的月份

    我有两个日期选择器字段 一个是 开始日期 另一个是 end date 我想要一个功能 在用户选择 开始日期 然后是 end date 日历应默认显示包含 开始日期 反之亦然 如果用户首先选择end date 日历为开始日期应显示包含所选的月
  • Spring Boot 2.7.1 与 JSF 2.2 (Mojarra) 和 Primefaces 6.2.9 集成

    我已经使用下面的堆栈进行了工作设置 春季MVC 5JSF Mojarra 2 2 14Primefaces 6 2 9 该应用程序是作为 WAR 构建的 它具有配置了 FacesServlet 的 web xml 来服务 xhtml 请求