如何使用自定义渲染器渲染复合组件?

Ang*_*gel 2 renderer composite-component jsf-2

我想知道如何通过Java渲染复合组件,我的意思是:

<myowntags:selectOneRadio>
  <f:selectItem itemValue="value0" itemLabel="This is the value 0" />
  <f:selectItem itemValue="value1" itemLabel="This is the value 1" />
  <f:selectItem itemValue="value2" itemLabel="This is the value 2" />
</myowntags:selectOneRadio>
Run Code Online (Sandbox Code Playgroud)

要么

<myowntags:selectOneRadio>
  <f:selectItems  value="#{controller.items}"  />
</myowntags:selectOneRadio>
Run Code Online (Sandbox Code Playgroud)

我想创建一个Java类来呈现它.

我知道如何在不使用复合的情况下渲染自定义组件,但是因为要渲染组件,我必须在块上指定一些值:

<renderer>
    <component-family>javax.faces.SelectBoolean</component-family>
    <renderer-type>javax.faces.Checkbox</renderer-type>
    <renderer-class>com.myapp.CustomCheckboxRenderer</renderer-class>
</renderer>
Run Code Online (Sandbox Code Playgroud)

然后我迷路了,因为我不知道复合组件的render标签内的那些参数的值.

提前谢谢,天使.

Bal*_*usC 13

首先,您需要一个支持组件,该组件实现NamingContainer"javax.faces.NamingContainer"作为组件系列返回.这是复合组件所必需的,您无法更改该组件.该UINamingContainer实施已经这样做,所以,如果你可以从它延伸.

@FacesComponent("mySelectOneRadio")
public class MySelectOneRadio extends UINamingContainer {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

或者,如果你更想从延长UISelectOne,那么你就必须实现NamingContainer接口,并确保您返回UINamingContainer.COMPONENT_FAMILYgetFamily()覆盖.

然后,您需要指定它<cc:interface componentType>.

<cc:interface componentType="mySelectOneRadio">
Run Code Online (Sandbox Code Playgroud)

请注意,在此步骤中,您已经可以通过Java执行呈现(编码).只需覆盖该encodeChildren()方法即可.

@FacesComponent("mySelectOneRadio")
public class MySelectOneRadio extends UINamingContainer {

    @Override
    public void encodeChildren(FacesContext context) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        writer.startElement("div", this);
        writer.writeText("hello world", null);
        writer.endElement("div");
    }

}
Run Code Online (Sandbox Code Playgroud)

回到你的具体问题,你想要有一个独立的Renderer课程.没关系.为此您需要扩展Renderer:

@FacesRenderer(componentFamily=UINamingContainer.COMPONENT_FAMILY, rendererType=MySelectOneRadioRenderer.RENDERER_TYPE)
public class MySelectOneRadioRenderer extends Renderer {

    public static final String RENDERER_TYPE = "com.example.MySelectOneRadio";

    @Override
    public void encodeChildren(FacesContext context, UIComponent component) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        writer.startElement("div", component);
        writer.writeText("hello world", null);
        writer.endElement("div");
    }

}
Run Code Online (Sandbox Code Playgroud)

背衬部件应以正确注册此渲染器为默认渲染如下方法来改变(不重写getRendererType()方法,否则你或其他人将无法通过改变这个!<renderer>faces-config.xml):

@FacesComponent("myComposite")
public class MyComposite extends UINamingContainer {

    public MyComposite() {
        // Set default renderer.
        setRendererType(MySelectOneRadioRenderer.RENDERER_TYPE);
    }

}
Run Code Online (Sandbox Code Playgroud)

请注意,多亏了@FacesRenderer,你不需要麻烦faces-config.xml.


无论您选择哪种方式对孩子进行编码,您都可以获得组件的子项UIComponent#getChildren().当你在MySelectOneRadio组件内部时:

if (getChildCount() > 0) {
    for (UICompnent child : getChildren()) {
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

或者当你在MySelectOneRadioRenderer渲染器内:

if (component.getChildCount() > 0) {
    for (UICompnent child : component.getChildren()) {
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

要委托组件自己的默认呈现,请调用super.encodeChildren()component.encodeChildren().要委托子级自己的默认呈现,请调用child.encodeAll().

也可以看看: