如何使用"Faces.includeCompositeComponent"动态添加组件?Websphere 8 和 ICEFaces 3



我正在尝试使用OmniFaces Faces.includeCompositeComponent(...)的小改编将复合组件动态添加到另一个UIComponnt。我试图重新创建这个问题的行为,但它不起作用。

改编方法的代码如下(我从 OmniFaces v1.6 中获取(

/**
   * Create and include the composite component of the given library ane
   * resource name as child of the given UI component parent and return the
   * created composite component. This has the same effect as using
   * <code>&lt;my:resourceName&gt;</code>. The given component ID must be unique
   * relative to the current naming container parent and is mandatory for
   * functioning of input components inside the composite, if any.
   * 
   * @param parent The parent component to include the composite component in.
   * @param libraryName The library name of the composite component.
   * @param resourceName The resource name of the composite component.
   * @param id The component ID of the composite component.
   * @return The created composite component, which can if necessary be further
   *         used to set custom attributes or value expressions on it.
   * @since 1.5
   */
  public static UIComponent includeCompositeComponent(UIComponent parent, String libraryName, String resourceName, String id)
  {
    // Prepare.
    FacesContext context = FacesContext.getCurrentInstance();
    Application application = context.getApplication();
    FaceletContext faceletContext = (FaceletContext) context.getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
    // This basically creates <ui:component> based on <composite:interface>.
    Resource resource = application.getResourceHandler().createResource(resourceName, libraryName);
    UIComponent composite = application.createComponent(context, resource);
    composite.setId(id); // Mandatory for the case composite is part of UIForm!
                         // Otherwise JSF can't find inputs.
    // This basically creates <composite:implementation>.
    UIComponent implementation = application.createComponent(UIPanel.COMPONENT_TYPE);
    implementation.setRendererType("javax.faces.Group");
    composite.getFacets().put(UIComponent.COMPOSITE_FACET_NAME, implementation);
    // Now include the composite component file in the given parent.
    parent.getChildren().add(composite);
    parent.pushComponentToEL(context, composite); // This makes #{cc} available.
    try
    {
      faceletContext.includeFacelet(implementation, resource.getURL());
    }
    catch (IOException e)
    {
      throw new FacesException(e);
    }
    finally
    {
      parent.popComponentFromEL(context);
    }
    return composite;
 }

这就是我尝试使用它的方式

JSFUtils.includeCompositeComponent(panelGroup, "comp", 
   "../inc-templates/test.xhtml", JSFUtils.createUniqueId());

另外,我创建了"test.xhtml"文件并将其放在WEB-INF/inc-templates/test下.xhtml以下是其内容:

测试.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:cc="http://java.sun.com/jsf/composite"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:p="http://primefaces.org/ui"
      xmlns:composite="http://java.sun.com/jsf/composite">
    <!-- INTERFACE -->
    <cc:interface>
    </cc:interface>
    <!-- IMPLEMENTATION -->
    <cc:implementation>
        <h:outputText value="TEST"/>
    </cc:implementation>
</html>

最后但并非最不重要的一点是,我将 test.xhtml 标签添加到 taglib.xml,如下所示:

<tag>
  <tag-name>test</tag-name>
  <source>../inc-templates/test.xhtml</source>
</tag>

问题是,当我运行代码并尝试插入组件时,我得到以下异常

Caused by: java.lang.NullPointerException: Argumentfehler: Parameter componentResource ist null
        at com.sun.faces.util.Util.notNull(Util.java:314)
        at com.sun.faces.application.ApplicationImpl.createComponent(ApplicationImpl.java:928)
        at org.my.JSFUtils.includeCompositeComponent(JSFUtils.java:496)

org.my.JSFUtils.includeCompositeComponent(JSFUtils.java:496(中的行完全指的是代码行UIComponent composite = application.createComponent(context, resource);,这实际上表明资源不是在上一行中创建的:Resource resource = application.getResourceHandler().createResource(resourceName, libraryName);

有谁知道为什么会发生这种情况?我什至尝试将资源的位置更改为 inc-templates/test.xhtml甚至在调用该方法时只是测试.xhtml但没有任何效果......我总是得到同样的错误。

顺便说一下,我正在尝试在 Websphere 8 中进行部署,并且使用的是 ICEFaces 3。

提前感谢!

您似乎正在将复合组件与标记文件混合在一起。要查看和理解两者之间的区别,请前往此答案及其内部链接:何时使用 <ui:include>、标记文件、复合组件和/或自定义组件?

您的 XHTML 文件清楚地表示了一个复合组件。但是,您将其视为标记文件。它像标签文件一样放置在/WEB-INF文件夹中,而不是像真正的复合材料一样放置在/resources文件夹中。它已注册在像标记文件这样的.taglib.xml文件中,而不是像真正的复合文件那样无配置。

目前还不完全清楚你到底想要什么。是否要以编程方式包含包含文件、标记文件或复合组件?假设您实际上希望以编程方式包含一个复合组件(否则includeCompositeComponent()的整个用法完全没有意义(。在这种情况下,将 XHTML 文件移动到/resources文件夹中,如所有复合组件教程所示(这样,当您在任何任意 XHTML 模板客户端中使用 <my:test> 时,它也可以真正工作(:

WebContent
 |-- WEB-INF
 |    `-- lib
 |-- resources
 |    `-- mycomponents
 |         `-- test.xhtml   <---
 `-- some.xhtml

摆脱.taglib.xml中不必要的条目,最后使用null的库名称和/mycomponents/test.xhtml的资源名称包含它。

includeCompositeComponent(parent, null, "/mycomponents/test.xhtml", uniqueId);

最新更新