Как использовать значения перечисления в f: selectItem (s)


103

Я хочу создать раскрывающийся список selectOneMenu, чтобы я мог выбрать статус своего вопроса. Можно ли сделать f: selectItem более гибким с учетом того, что произойдет, если порядок перечислений изменится, и если список будет большим? Могу ли я сделать это лучше? И можно ли автоматически «выбрать» тот пункт, который есть в вопросе?

Enum класс

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>

Ответы:


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[]или List<SelectItem>, 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 05

Спасибо, BalusC. Можно ли каким-то образом заменить # {data.statuses} классом enum без использования компонента поддержки (например, value = "# {org.myproject.Status.values}")?
sasynkamil 06

@BalusC ты уверен? Я использую GF 3.1.2 (Mojarra JSF 2.1.6).
sasynkamil 06

4

Вы можете использовать <f:selectItems value="#{carBean.carList}" />и вернуть список SelectItemэкземпляров, которые обертывают перечисление (используйте Status.values()для получения всех возможных значений).


2

Вы можете использовать следующую служебную функцию el, чтобы получить значения перечисления и использовать их, SelectOneMenuнапример, в. Нет необходимости создавать бины и стандартные методы.

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;
    }
}

Зарегистрируйте его как функцию el в файле taglib:

<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.
Roland
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.