【问题标题】:How to use enum values in f:selectItem(s)如何在 f:selectItem(s) 中使用枚举值
【发布时间】:2012-01-04 00:06:02
【问题描述】:

我想创建一个 selectOneMenu 下拉菜单,以便我可以选择我的问题的状态。考虑到如果枚举的顺序发生变化以及列表很大时会发生什么,是否可以使 f:selectItem 更加灵活?我可以做得更好吗?是否可以自动“选择”问题所具有的项目?

枚举类

public enum Status {
    SUBMITTED,
    REJECTED,
    APPROVED
}

问题实体

@Enumerated(EnumType.STRING)
private Status status;

JSF

<div class="field">
    <h:outputLabel for="questionStatus" value="Status" />
    <h:selectOneMenu id="questionStatus" value="#{bean.question.status}" >
        <f:selectItem itemLabel="Submitted" itemValue="0" />
        <f:selectItem itemLabel="Rejected" itemValue="1" />
        <f:selectItem itemLabel="Approved" itemValue="2" />
    </h:selectOneMenu>
    <hr />
</div>

【问题讨论】:

    标签: jsf jsf-2 enums selectonemenu


    【解决方案1】:

    JSF 有一个用于enum 的内置转换器,所以应该这样做:

    @Named
    @ApplicationScoped
    public class Data {
    
        public Status[] getStatuses() {
            return Status.values();
        }
    
    }
    

    <h:selectOneMenu value="#{bean.question.status}" >
        <f:selectItems value="#{data.statuses}" />
    </h:selectOneMenu>
    

    (注意:由于 JSF 2.0 不再需要提供 SelectItem[]List&lt;SelectItem&gt;T[]List&lt;T&gt; 也被接受,您可以通过 var 访问当前项目属性)

    如果您碰巧使用 JSF 实用程序库 OmniFaces,那么您可以使用 &lt;o:importConstants&gt; 代替 bean。

    <o:importConstants type="com.example.Status" />
    
    <h:selectOneMenu value="#{bean.question.status}" >
        <f:selectItems value="#{Status}" />
    </h:selectOneMenu>
    

    如果您也打算控制标签,可以将它们添加到 Status 枚举:

    public enum Status {
    
        SUBMITTED("Submitted"),
        REJECTED("Rejected"),
        APPROVED("Approved");
    
        private String label;
    
        private Status(String label) {
            this.label = label;
        }
    
        public String getLabel() {
            return label;
        }
    
    }
    

    <f:selectItems value="#{data.statuses}" var="status"
        itemValue="#{status}" itemLabel="#{status.label}" />
    

    或者,更好的是,使枚举值成为本地化资源包的属性键(需要 EL 3.0):

    <f:selectItems value="#{data.statuses}" var="status"
        itemValue="#{status}" itemLabel="#{text['data.status.' += status]}" />
    

    在与资源包 #{text} 关联的属性文件中使用它

    data.status.SUBMITTED = Submitted
    data.status.REJECTED = Rejected
    data.status.APPROVED = Approved
    

    【讨论】:

    • 一件事BalusC,是否可以“选择”/查看问题的默认状态(例如,当您正在编辑问题时,您已经将问题的状态设置为)
    • 在上面的例子中,当#{bean.question.status} 有一个有效的枚举值时,JSF 默认会这样做。您不需要做任何事情来确保 question 具有预填充的正确状态属性。
    • @BalusC 如何从 JSF 访问序数值?
    • 如果您像我一样遇到+= status 的数字格式异常,请尝试按照@Ziletka 的建议使用.concat(status)
    • 如果你更喜欢 java.util.List 你可以修改 getStatuses() 返回类型为 List 并返回 Arrays.asList(Status.values());
    【解决方案2】:

    您可以使用以下实用程序 el 函数来获取枚举值并在 SelectOneMenu 中使用它们。无需创建 bean 和样板方法。

    public final class ElEnumUtils
    {
        private ElEnumUtils() { }
    
        /**
         * Cached Enumerations, key equals full class name of an enum
         */
        private final static Map<String, Enum<?>[]> ENTITY_ENUMS = new HashMap<>();;
    
        /**
         * Retrieves all Enumerations of the given Enumeration defined by the
         * given class name.
         *
         * @param enumClassName Class name of the given Enum.
         *
         * @return
         *
         * @throws ClassNotFoundException
         */
        @SuppressWarnings("unchecked")
        public static Enum<?>[] getEnumValues(final String enumClassName) throws ClassNotFoundException
        {
            // check if already cached - use classname as key for performance reason
            if (ElEnumUtils.ENTITY_ENUMS.containsKey(enumClassName))
                return ElEnumUtils.ENTITY_ENUMS.get(enumClassName);
    
            final Class<Enum<?>> enumClass = (Class<Enum<?>>) Class.forName(enumClassName);
    
            final Enum<?>[] enumConstants = enumClass.getEnumConstants();
    
            // add to cache
            ElEnumUtils.ENTITY_ENUMS.put(enumClassName, enumConstants);
    
            return enumConstants;
        }
    }
    

    在taglib文件中注册为el函数:

    <function>
        <description>Retrieves all Enumerations of the given Enumeration defined by the given class name.</description>
        <function-name>getEnumValues</function-name>
        <function-class>
            package.ElEnumUtils
        </function-class>
        <function-signature>
            java.lang.Enum[] getEnumValues(java.lang.String)
        </function-signature>
    </function>
    

    最后这样称呼它:

    <p:selectOneMenu value="#{bean.type}">
        <f:selectItems value="#{el:getEnumValues('package.BeanType')}" var="varEnum" 
            itemLabel="#{el:getEnumLabel(varEnum)}" itemValue="#{varEnum}"/>
    </p:selectOneMenu>
    

    类似于 BalusC 的答案,您应该使用具有本地化枚举标签的资源包,并且为了更简洁的代码,您还可以创建类似 getEnumLabel(enum)

    的函数

    【讨论】:

    • 不需要“函数”(方法更多),当您可以使用 #{myBundle[enumName.i18nKey]} 然后将 i18n 键作为属性放入您的枚举时:BLA_TYPE("SOME_BLA_TYPE_KEY") by BLA_TYPE 是枚举可以使用,SOME_BLA_TYPE_KEY 是 i18n 键。
    【解决方案3】:

    对于本地化,我们也可以使用这个解决方案:

    public enum Status { SUBMITTED, REJECTED, APPROVED }
    
    data.status.SUBMITTED=Submitted
    data.status.REJECTED=Rejected
    data.status.APPROVED=Approved
    
    <h:selectOneMenu value="#{bean.question.status}" >
        <f:selectItems
            value="#{data.statuses}"
            var="status"
            itemValue="#{status}"
            itemLabel="#{text['data.status.'.concat(status)]}" />
    </h:selectOneMenu>
    

    所以本地化字符串的资源路径没有硬编码在 Enum 中。

    【讨论】:

    • 请注意,此语法仅从“相对”新的 EL 2.2 开始受支持。否则,您可以随时获取 &lt;c:set&gt;&lt;ui:param&gt; 或自制自定义 EL 函数。
    • 谢谢 BalusC。是否可以在不使用支持 bean 的情况下以某种方式将 #{data.statuses} 替换为枚举类(例如 value="#{org.myproject.Status.values}")?
    • @BalusC 你确定吗?我正在使用 GF 3.1.2 (Mojarra JSF 2.1.6)。
    【解决方案4】:

    您可以使用&lt;f:selectItems value="#{carBean.carList}" /&gt; 并返回一个包含枚举的SelectItem 实例列表(使用Status.values() 获取所有可能的值)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-10
      • 2018-05-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多