如何扩展枚举属性的 UISelectOne 组件以自动填充所有枚举值作为选择项?

发布于 2024-12-09 15:16:28 字数 719 浏览 0 评论 0原文

我想使用简化的选择一个标签,它将自动生成枚举的选择项列表。因此,结果将是:

<s:enumSelectOneMenu value="#{myBean.enumValue}"/>

因此,在组件内部,我可以获取枚举类型并使用反射获取所有枚举值。因此,基本上我需要重写 UiSelectOne 中唯一的一种方法 validateValue(..) 并将 UiSelectItems 列表作为子项放在那里(在与在 Tomahawk 中完成的方式相同,请参阅 SelectOneLanguage 组件)。

但还应该做什么呢?我需要在我自己的 taglib.xml 中描述标签属性,但 jsf-impl.jar 不包含 Facelets xml - 仅 taglib 文件,所以我不能简单地从那里复制所有内容。另外,如果我在 taglib.xml 中静态描述标签 - 我将不得不在每个新版本的 JSF 上手动更新它,这一点都不好。那么,在 JSF 中扩展组件并避免大量手动复制粘贴工作的最佳方法是什么?

PS我正在使用JSF 2.0,但是composite-facelets方式不适合我,因为它会产生很多问题,因为复合元素是由NamingContainer组件包装的。所以我只需要“老派”方式来创建自定义组件。

谢谢。

I want to use simplified select one tag, which would generate select items list for enums automatically. So, the result would be:

<s:enumSelectOneMenu value="#{myBean.enumValue}"/>

So, inside the component I can get the enum type and get all enum values using reflection. So, basically I need to override the only one method validateValue(..) from UiSelectOne and put the UiSelectItems list as the child there (in the same manner as it is done in Tomahawk, see SelectOneLanguage component).

But what else should be done? I need to describe tag attributes in my own taglib.xml but jsf-impl.jar does not contain facelets xml - only taglib file, so I cannot simply copy everything from there. Also, if I statically describe tag in my taglib.xml - I will have to update it manually on each new version of JSF, which is not good at all. So, which is the best way to extend the component in JSF and avoid lots of manual copy-paste work?

P.s. I'm using JSF 2.0, but composite-facelets way is not suitable for me as it produces lots of problems as composite element is wrapped by NamingContainer component. So I need only "oldschool" way to create custom components.

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

吹梦到西洲 2024-12-16 15:16:28

扩展某些 JSF 组件并添加行为而不丢失属性的最佳(但不是最简单)方法之一是使用 PrimeFaces JSF 插件。有关它的一些信息如下:http://code.google.com/p/primefaces/维基/BuildingFromSource。虽然它有一些硬编码值(facelets taglib 的名称和输出目录的方式,生成的 taglib 放置在其中)并且可以在本地更改和重建
这是 PF jsf 插件的示例

   <!-- Primefaces maven plugin -->
            <plugin>
                <groupId>org.primefaces</groupId>
                <artifactId>maven-jsf-plugin</artifactId>
                <version>1.2.1-SNAPSHOT</version>
                <executions>
                    <execution>
                        <id>generate-ui</id>
                        <phase>generate-sources</phase>
                        <configuration>
                            <uri>http://www.mycompany.com/tags</uri>
                            <name>rstk-tag</name>
                            <jsfVersion>2</jsfVersion>
                            <templatesDir>src/main/java-templates</templatesDir>
                            <componentConfigsDir>src/main/resources-maven-jsf/ui</componentConfigsDir>
                            <!-- <standardFacesConfig>src/main/resources-maven-jsf/standard-faces-config.xml</standardFacesConfig> -->
<!-- These are new attributes added manually to plugin source code! -->
                            <standardFaceletsTaglib>src/main/resources-maven-jsf/standard-facelets-taglib.xml</standardFaceletsTaglib>
                            <faceletsOutputDirectory>target/generated-sources/maven-jsf-plugin/META-INF</faceletsOutputDirectory>
                        </configuration>
                        <goals>
                            <goal>generate-components</goal>
                            <goal>generate-facelets-taglib</goal>
                        </goals>
                    </execution>                    
                </executions>
            </plugin>

之后,可以使用以下元数据 xml 进行生成:

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE component SYSTEM "../misc/component.dtd" [
<!ENTITY standard_uicomponent_attributes        SYSTEM "../entities/standard_uicomponent_attributes.xml">
<!ENTITY output_component_attributes            SYSTEM "../entities/output_component_attributes.xml">
<!ENTITY input_component_attributes             SYSTEM "../entities/input_component_attributes.xml">
]>
<component>
    <tag>enumSelectOneMenu</tag>
    <tagClass>com.rstk.kasko.component.EnumSelectOneMenuTag</tagClass>
    <componentClass>com.rstk.kasko.component.EnumSelectOneMenu</componentClass>
    <componentType>com.rstk.kasko.component.EnumSelectOneMenu</componentType>
    <componentFamily>javax.faces.SelectOne</componentFamily>
    <rendererType>javax.faces.Menu</rendererType>
    <parent>javax.faces.component.html.HtmlSelectOneMenu</parent>
    <description>The tag for select one menu, which renders the enumerations list. No children necessary for this</description>
    <attributes>
        &input_component_attributes;
    </attributes>

</component>

这与 EnumSelectOneMenuTemplate.java(插入到生成的组件代码中的模板)一起允许生成:

  1. 带有所有标准 html 选择的 taglib.xml一个菜单属性
  2. 组件类,包含用于渲染 clidhren 的自定义逻辑:

    public class EnumSelectOneMenu extends HtmlSelectOneMenu {
    ... // Generated staff here
    public boolean getRendersChildren() {
            return true;
        }

        /**
         * @see javax.faces.component.UIComponentBase#encodeBegin(javax.faces.context.FacesContext)
         */
        @Override
        public void encodeBegin(FacesContext context) throws IOException {
            super.encodeBegin(context);

            if (context.isPostback()) {
                return;
            }

            UISelectItems selectItems = new UISelectItems();
            try {
                selectItems.setValue(getEnumValuesList());
            } catch (Exception e) {
                log.error("Failed to create enum list", e);
            }
            getChildren().add(selectItems);

        }

        /**
         * Creates the list of select items of format [ENUM, enum.getDisplay()] 
         * @return
         */
        private List getEnumValuesList() {
            List result = new ArrayList();
            ValueExpression ve = getValueExpression("value");
            Class enumClass = ve.getType(getFacesContext().getELContext());
            Method method = ReflectionUtils.findMethod(enumClass, "getDisplay", null);
            for (Object e : ve.getType(getFacesContext().getELContext()).getEnumConstants()) {
                result.add(new SelectItem(e, (String) ReflectionUtils.invokeMethod(method, e)));
            }
            return result;
        }
    }

然后该组件可以用作简单的 JSF 选择一个组件(具有所有标准属性),但不需要每次都添加选择项并允许任何其他孩子都可以放在那里:

<s:enumSelectOneMenu value="#{polis.osMatrixType}" id="registryType">
        <p:ajax listener="#{osagoPolisBean.rollOsagoEndDate}" update="osagoUsagePeriod" process="osagoTable" event="change"/>                               
</s:enumSelectOneMenu>  

One of best (but not the easiest) way to extend some JSF components and add the behaviour while not loosing attributes is using PrimeFaces JSF plugin. Some information about it is here: http://code.google.com/p/primefaces/wiki/BuildingFromSource. Though it has some hardcoded values (name of facelets taglib and way to output directory, where generated taglib is put) and can be changed and rebuilt locally
Here is the example of PF jsf plugin

   <!-- Primefaces maven plugin -->
            <plugin>
                <groupId>org.primefaces</groupId>
                <artifactId>maven-jsf-plugin</artifactId>
                <version>1.2.1-SNAPSHOT</version>
                <executions>
                    <execution>
                        <id>generate-ui</id>
                        <phase>generate-sources</phase>
                        <configuration>
                            <uri>http://www.mycompany.com/tags</uri>
                            <name>rstk-tag</name>
                            <jsfVersion>2</jsfVersion>
                            <templatesDir>src/main/java-templates</templatesDir>
                            <componentConfigsDir>src/main/resources-maven-jsf/ui</componentConfigsDir>
                            <!-- <standardFacesConfig>src/main/resources-maven-jsf/standard-faces-config.xml</standardFacesConfig> -->
<!-- These are new attributes added manually to plugin source code! -->
                            <standardFaceletsTaglib>src/main/resources-maven-jsf/standard-facelets-taglib.xml</standardFaceletsTaglib>
                            <faceletsOutputDirectory>target/generated-sources/maven-jsf-plugin/META-INF</faceletsOutputDirectory>
                        </configuration>
                        <goals>
                            <goal>generate-components</goal>
                            <goal>generate-facelets-taglib</goal>
                        </goals>
                    </execution>                    
                </executions>
            </plugin>

After this the following metadata xml can be used for generation:

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE component SYSTEM "../misc/component.dtd" [
<!ENTITY standard_uicomponent_attributes        SYSTEM "../entities/standard_uicomponent_attributes.xml">
<!ENTITY output_component_attributes            SYSTEM "../entities/output_component_attributes.xml">
<!ENTITY input_component_attributes             SYSTEM "../entities/input_component_attributes.xml">
]>
<component>
    <tag>enumSelectOneMenu</tag>
    <tagClass>com.rstk.kasko.component.EnumSelectOneMenuTag</tagClass>
    <componentClass>com.rstk.kasko.component.EnumSelectOneMenu</componentClass>
    <componentType>com.rstk.kasko.component.EnumSelectOneMenu</componentType>
    <componentFamily>javax.faces.SelectOne</componentFamily>
    <rendererType>javax.faces.Menu</rendererType>
    <parent>javax.faces.component.html.HtmlSelectOneMenu</parent>
    <description>The tag for select one menu, which renders the enumerations list. No children necessary for this</description>
    <attributes>
        &input_component_attributes;
    </attributes>

</component>

This together with EnumSelectOneMenuTemplate.java (the template, which is inserted into generated component code) allows to generate:

  1. taglib.xml with ALL standard html select one menu attributes
  2. The component class, which contains custom logics for rendering clidhren:

    public class EnumSelectOneMenu extends HtmlSelectOneMenu {
    ... // Generated staff here
    public boolean getRendersChildren() {
            return true;
        }

        /**
         * @see javax.faces.component.UIComponentBase#encodeBegin(javax.faces.context.FacesContext)
         */
        @Override
        public void encodeBegin(FacesContext context) throws IOException {
            super.encodeBegin(context);

            if (context.isPostback()) {
                return;
            }

            UISelectItems selectItems = new UISelectItems();
            try {
                selectItems.setValue(getEnumValuesList());
            } catch (Exception e) {
                log.error("Failed to create enum list", e);
            }
            getChildren().add(selectItems);

        }

        /**
         * Creates the list of select items of format [ENUM, enum.getDisplay()] 
         * @return
         */
        private List getEnumValuesList() {
            List result = new ArrayList();
            ValueExpression ve = getValueExpression("value");
            Class enumClass = ve.getType(getFacesContext().getELContext());
            Method method = ReflectionUtils.findMethod(enumClass, "getDisplay", null);
            for (Object e : ve.getType(getFacesContext().getELContext()).getEnumConstants()) {
                result.add(new SelectItem(e, (String) ReflectionUtils.invokeMethod(method, e)));
            }
            return result;
        }
    }

Then this component can be used as simple JSF select one component (with ALL standard attributes), but does not require select items to be added each time and allows any other childre be placed there:

<s:enumSelectOneMenu value="#{polis.osMatrixType}" id="registryType">
        <p:ajax listener="#{osagoPolisBean.rollOsagoEndDate}" update="osagoUsagePeriod" process="osagoTable" event="change"/>                               
</s:enumSelectOneMenu>  
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文