如何使用注释而不是 XML 在嵌入式 Tomcat 中创建自定义组件标签

How can I use annotations instead of XML to create a custom component tag in embedded Tomcat

编辑:重现此问题所需的唯一技术是 JSF 2.2Spring Boot 1.2.1 + 其嵌入式 Tomcat 8.0.5 服务器。此问题中列出的所有其他内容只是为了提供我正在使用的技术的背景信息。

Update #2: Following along with BalusC's thoughts, I ported my sample custom component into a barebones Servlet 3.1 + JSF 2.2 application. You can find the code for it on Github here.

This simple case does not exhibit the issue I'm describing here. The @FacesComponent annotation works. This heavily implies that the problem is being caused either by Spring 4.1.2 or Spring Boot itself. It's getting late, so I'll be investigating this further tomorrow.

TL;DR:我想使用 @FacesComponent 及其属性替换 foundation-components-html.taglib.xmlfaces-config.xml

中的 <component> 条目

我目前有使用 XML 定义在我的项目中工作的自定义组件。我最近了解到 JSF 2.2 引入了 feature,它完全消除了对 XML 的需要。我很想使用它,但是当我纯粹使用注释时,它们会被 JSF 忽略。原始标签出现在我的 HTML.

(即<custom:paragraph></custom:paragraph>

我在 Github 上托管的我的沙箱中演示了这个问题。如果你想尝试一下,我会在这篇 post.

的底部解释如何

您只需删除 foundation-components-html.taglib.xml,并注释掉 <component> 和 运行 应用程序的 faces-config.xml 条目即可遇到问题。我将其保留在 'functioning' 状态,以便任何希望提供帮助的人都有一个简单、可验证的正确起点。只需点击 http://localhost:8080

Technologies Used:

  • Spring Boot 1.2.1

  • JSF 2.2 via Mojarra 2.2.6

  • Embedded Tomcat 8.0.5

注意: 请记住,此设置当前有效,但它在 taglib 和 faces-config 条目上 运行ning!我的问题是如何使用 JSF 2.2

中的最新功能删除这些依赖项

Full Project

Custom Component

package foundation.components;

import java.io.IOException;

import javax.faces.component.FacesComponent;

import javax.faces.component.UIComponentBase;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;

/**
 * The Paragraph Component
 * @author Seth Ellison
 */
@FacesComponent(value=UIParagraph.COMPONENT_TYPE, createTag=true, tagName="paragraph", namespace="http://www.blah.com/components/html")
public class UIParagraph extends UIComponentBase {

public static final String COMPONENT_TYPE = "foundation.components.Paragraph";

private String value;
private String styleClass;

@Override
public void encodeBegin(final FacesContext facesContext) throws IOException {

    // Encode Implementation Omitted for Brevity. 
}

@Override
public String getFamily() {        
    return "blah.components.family";
}

// Getters/Setters...

}

Taglib Definition

<facelet-taglib version="2.2"
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-facelettaglibrary_2_2.xsd">

    <namespace>http://www.blah.com/components/html</namespace>

    <tag>
        <tag-name>paragraph</tag-name>
        <component>
            <component-type>foundation.components.Paragraph</component-type>
        </component>
    </tag>
</facelet-taglib>

Faces Config

<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" metadata-complete="false">

    <component>
        <component-type>foundation.components.Paragraph</component-type>
        <component-class>foundation.components.UIParagraph</component-class>
    </component>  
</faces-config>

XHTML Template(为清楚起见,进行了精简)

<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:jsf="http://xmlns.jcp.org/jsf"
  xmlns:custom="http://www.blah.com/components/html">

    <head jsf:id="head"></head>
    <body jsf:id="body">
       <custom:paragraph value="This is a template for a simple marketing or informational website. It includes a large callout called a jumbotron and three supporting pieces of content. Use it as a starting point to create something more unique." />
    </body>
</html>

如果您想 运行 这个,最简单的方法是下载 Spring 工具套件,从 Github 中获取代码,右键单击该项目,然后运行 它作为 Spring 启动应用程序。当 JPA 配置启动时,您会收到连接错误,因为您(很可能)没有 运行 本地 MySQL 服务器。别担心这个。根本不需要访问索引页面并检查标签状态。我经常 运行 应用程序在有和没有数据库的情况下启动都没有不良影响。最后,要让 PrettyFaces 与 Spring Boot 配合使用,您必须从 target/classes 创建一个 Symbolic Link 或一个 Hard Link 到 WEB-INF/ -- PrettyFaces被编码为在扫描注释时在 WEB-INF/classes 或 WEB-INF/lib 中查找。

BalusC 的片段

这个函数存在于一个标有@Configuration的class中,实现了ServletContextAware

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

好的,我知道是什么导致了这个问题。

今天早上我坐下来思考代码的工作 Servlet 3.1 版本和损坏的 Spring Boot 版本之间的区别。主要区别在于代码的编写方式 运行。嵌入式服务器与独立服务器。

Spring Boot's embedded Tomcat server was the cause.

当我根据 this answer 切换我的沙盒时,一切正常打开,我的自定义组件完全依赖 @FacesComponent 注释!

我认为这与 类 的组织方式有关 post - 在嵌入式服务器上启动与离散部署到 Pivotal Tomcat 服务器。在那种情况下,JSF 的注解扫描器似乎会简单地忽略注解。