如何在f:selectItem(s)中使用枚举值


103

我想创建一个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>

Answers:


210

JSF具有的内置转换器enum,因此应该这样做:

@ManagedBean
@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[]or List<SelectItem>,a T[]List<T>也被接受,您可以按var属性访问当前项)

如果碰巧使用了JSF实用程序库OmniFaces,那么可以使用<o:importConstants>而不是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的一件事是,有可能默认情况下“选择” /查看问题的状态(例如,当您编辑问题时,您已经将问题的状态设置为某种情况)
LuckyLuke

在上面的示例中,默认情况下,JSF将在#{bean.question.status}具有有效的枚举值时执行此操作。您无需做任何确保question已预先填充正确的status属性的事情。
BalusC

@BalusC如何从JSF访问序数值?
jacktrades

2
如果像我一样,您遇到的数字格式异常+= status,请尝试.concat(status)按照@Ziletka的建议使用。
whistling_marmot

如果您更喜欢java.util.List,则可以将getStatuses()返回类型修改为List <Status>并返回Arrays.asList(Status.values());。
stakahop

16

对于本地化,我们还可以使用以下解决方案:

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中进行硬编码。


1
请注意,仅从“相对”新的EL 2.2开始才支持此语法。否则,您始终可以获取<c:set><ui:param>自制的自定义EL功能。
BalusC

谢谢BalusC。是否可以通过某种方式用枚举类替换#{data.statuses},而不使用后备bean(例如,value =“#{org.myproject.Status.values}”)?
Ziletka

您确定@BalusC吗?我正在使用GF 3.1.2(Mojarra JSF 2.1.6)。
Ziletka

4

您可以使用 <f:selectItems value="#{carBean.carList}" />并返回SelectItem包装枚举的实例的列表(用于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键。
罗兰
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.