Spring 启动时出现 Primefaces 问题

Spring Boot with Primefaces issues

Spring 引导 2.4.1 Primefaces 8

我有两个问题: h:outputStylesheet 不呈现 link 标签,所以我在浏览器中没有获得任何样式。 primefaces 菜单栏正在呈现一个普通的旧 ul 列表。

<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.4.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>org.gca</groupId>
    <artifactId>GCA-WEB</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>GCA-WEB</name>
    <description>Website for Gleneagle Civic Association (HOA)</description>

    <properties>
        <java.version>11</java.version>
        <primefaces.version>8.0</primefaces.version>
        <jsf.ver>2.2.20</jsf.ver>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.primefaces</groupId>
            <artifactId>primefaces</artifactId>
            <version>${primefaces.version}</version>
        </dependency>
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>${jsf.ver}</version>
        </dependency>
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-impl</artifactId>
            <version>${jsf.ver}</version>
        </dependency>
        <dependency>
            <groupId>javax.el</groupId>
            <artifactId>javax.el-api</artifactId>
            <version>3.0.0</version>
            <scope>provided</scope>
        </dependency>
               
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

JSF 配置:

package org.gca.config;

import com.sun.faces.config.ConfigureListener;
import java.util.Arrays;
import javax.faces.webapp.FacesServlet;
import javax.servlet.ServletContext;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
public class JsfConfig {

    @Bean
    ServletRegistrationBean jsfServletRegistration(ServletContext servletContext) {
        //spring boot only works if this is set
        servletContext.setInitParameter("com.sun.faces.forceLoadConfiguration", Boolean.TRUE.toString());

        //registration
        ServletRegistrationBean srb = new ServletRegistrationBean();
        srb.setServlet(new FacesServlet());
        srb.setUrlMappings(Arrays.asList("*.xhtml"));
        srb.setLoadOnStartup(1);
        return srb;
    }

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

    @Bean
    public ViewResolver getViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setSuffix(".xhtml");
        return resolver;
    }
}

我手动创建了 webapps/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/web-facesconfig_2_2.xsd"
              version="2.2">

    <application>
        <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
    </application>

</faces-config>

模板:

<?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:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets">
    <h.head>
        <h:outputStylesheet library="css" name="gca.css"/>
        <title>
            <ui:insert name="title">GCA</ui:insert>
        </title>
        <ui:insert name="style"></ui:insert>
        <ui:insert name="script"> </ui:insert>
    </h.head>
    <h.body>
        <h:form id="bannerForm">
            <ui:insert name="banner">
                <h:panelGroup styleClass="bannerPanel" layout="block">
                    <h:panelGrid
                        id="bannerGrid" 
                        columns="2" columnClasses="bannerColLeft, bannerColRight"
                        style="margin: 0px;padding: 0px;width:100%;">
                        <h:graphicImage
                            url="/resources/images/GleneagleSign.png"
                            style="height: 100px;width: 100px;"/>
                        <h:outputText value="Gleneagle Civic Association"/>
                    </h:panelGrid>
                </h:panelGroup>
            </ui:insert>
            <ui:insert name="menu">
                <ui:include id="mnuIncld" src="gcaMenu.xhtml"/>
            </ui:insert>
        </h:form>
        <h:panelGroup id="workPanel" layout="block" styleClass="alignLeft" style="margin-top:100px;">
            <h:panelGrid id="wrkPnlGrd" columns="1" styleClass="alignLeft" columnClasses="workColumnLeft" rowClasses="workRow">
                <h:outputLabel id="ajaxErrMsg" styleClass="errorLeft"/>
                <ui:insert name="work">

                </ui:insert>
            </h:panelGrid>
        </h:panelGroup>
        <ui:insert name="bottomScript">

        </ui:insert>
    </h.body>
</html>

菜单:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html  xmlns="http://www.w3.org/1999/xhtml"
       xmlns:ui="http://java.sun.com/jsf/facelets"
       xmlns:p="http://primefaces.org/ui">
    <ui:composition id="mnuComp">
        <p:menubar>
            <p:menuitem value="Home" url="#"/>
            <p:submenu label="About GCA">
                <p:menuitem value="Leadership" action="/about/leadership"/>
                <p:menuitem value="Our History" action="/about/history"/>
                <p:menuitem value="Map of GCA" action="/about/map"/>
                <p:menuitem value="Surrounding HOAs" action="/about/hoas"/>
                <p:menuitem value="Related Links" action="/about/links"/>
            </p:submenu>
            <p:submenu label="Documents">
                <p:submenu label="Board Meetings">
                    <p:menuitem value="Board Meeting Agenda" action="/doc/board/agenda"/>
                    <p:menuitem value="Board Meeting Minutes" action="/doc/board/minutes"/>
                </p:submenu>
                <p:submenu label="Membership Meetings">
                    <p:menuitem value="Membership Meeting Minutes" action="/doc/member/minutes"/>
                </p:submenu>
                <p:submenu label="Architectural Control">
                    <p:menuitem value="Approval Process"  action="/doc/archCtl/approval"/>
                    <p:menuitem value="Variance Process"  action="/doc/archCtl/variance"/>
                    <p:menuitem value="House Color Standards"  action="/doc/archCtl/houseColors"/>
                    <p:menuitem value="Mailbox Specifications"  action="/doc/archCtl/mailbox"/>
                </p:submenu>
                <p:submenu label="Covenants">
                    <p:menuitem value="Covenants, Restrictions and Charges" action="/doc/covenant"/>                            
                    <p:menuitem value="Amendment One" action="/doc/covenant/ammendment1"/>                            
                    <p:menuitem value="Amendment Four" action="/doc/covenant/ammendment4"/>
                    <p:menuitem value="Rules &amp; Regulations" action="/doc/covenant/ruleRegs"/>
                    <p:menuitem value="Fine Schedule" action="/doc/covenant/findSchedule"/>
                </p:submenu>
            </p:submenu>
            <p:submenu label="Contact">
                <p:menuitem value="Feedback" action="/contact/feedback"/>
                <p:menuitem value="Join Mailing List" action="/contact/mailList"/>
            </p:submenu>
        </p:menubar>
        <p:growl id="messages"/>
    </ui:composition>
</html>

我还尝试以编程方式创建菜单,但菜单托管 Bean 未被实例化:

package org.gca.mbeans;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.primefaces.model.menu.DefaultMenuItem;
import org.primefaces.model.menu.DefaultMenuModel;
import org.primefaces.model.menu.DefaultSubMenu;
import org.primefaces.model.menu.MenuModel;
import org.springframework.stereotype.Component;

@Slf4j
@Getter
@Component
@ManagedBean(name = "menuBean")
@ViewScoped
public class MenuMB {

    private final MenuModel menuModel = new DefaultMenuModel();
    
    @PostConstruct
    public void postConstruct() {
        addMenu("Home");
        addMenu("About GCA", "Leadership", "Our History", "Map of GCA", "Surrounding HOAs", "Related Links");
        addMenu("Documents");
        addMenu("Contacts");
        log.debug("Added 4 menu items");
    }

    public DefaultSubMenu addMenu(String label, String... items) {
        return addMenu(null, label, items);
    }

    public DefaultSubMenu addMenu(DefaultSubMenu parentMenu,
            String label, String... items) {
        DefaultSubMenu theMenu = new DefaultSubMenu(label);
        for (Object item : items) {
            DefaultMenuItem mi = new DefaultMenuItem(item);
            mi.setUrl("#");
            theMenu.getElements().add(mi);
        }
        if (parentMenu == null) {
            menuModel.addElement(theMenu);
        } else {
            parentMenu.getElements().add(theMenu);
        }
        return theMenu;
    }

}

index.xhtml

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:p="http://primefaces.org/ui">
    <body>
        <ui:composition template="/gcaMain.xhtml">
            <ui:define name="work">
                <p:menubar model="#{menuBean.menuModel}"/>[enter image description here][1]
            </ui:define>
        </ui:composition>
    </body>
</html>

遵循@Melloware 建议:

pom.xml更新

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.joinfaces</groupId>
                <artifactId>joinfaces-dependencies</artifactId>
                <version>${joinfaces.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.primefaces.themes</groupId>
                <artifactId>overcast</artifactId>
                <version>${primefaces-theme.version}</version>
            </dependency>
        </dependencies>        
    </dependencyManagement>
........
        <dependency>
            <groupId>org.joinfaces</groupId>
            <artifactId>primefaces-spring-boot-starter</artifactId>
        </dependency>
<!--        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.primefaces</groupId>
            <artifactId>primefaces</artifactId>
            <version>${primefaces.version}</version>
        </dependency>
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>${jsf.ver}</version>
        </dependency>-->


删除了 JmsConfig 文件并删除了面孔-config.xml

更正了模板