Cách sử dụng các giá trị enum trong f: selectItem (s)


103

Tôi muốn tạo menu selectOneMenu thả xuống để có thể chọn trạng thái cho câu hỏi của mình. Có thể làm cho f: selectItem linh hoạt hơn khi xem xét điều gì sẽ xảy ra nếu thứ tự của các enum thay đổi và nếu danh sách lớn? Và tôi có thể làm điều này tốt hơn không? Và có thể tự động "chọn" mục mà câu hỏi có không?

Enum lớp

public enum Status {
    SUBMITTED,
    REJECTED,
    APPROVED
}

Thực thể câu hỏi

@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>

Câu trả lời:


210

JSF có một trình chuyển đổi nội trang enum, vì vậy điều này sẽ làm:

@ManagedBean
@ApplicationScoped
public class Data {

    public Status[] getStatuses() {
        return Status.values();
    }

}

với

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

(lưu ý: vì JSF 2.0 nên không cần cung cấp dấu SelectItem[]hoặc List<SelectItem>, a T[]List<T>cũng được chấp nhận và bạn có thể truy cập mục hiện tại theo varthuộc tính)

Nếu bạn tình cờ sử dụng thư viện tiện ích JSF OmniFaces , thì bạn có thể sử dụng <o:importConstants>thay vì bean.

<o:importConstants type="com.example.Status" />

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

Nếu bạn cũng có ý định kiểm soát các nhãn, bạn có thể thêm chúng vào Statusenum:

public enum Status {

    SUBMITTED("Submitted"),
    REJECTED("Rejected"),
    APPROVED("Approved");

    private String label;

    private Status(String label) {
        this.label = label;
    }

    public String getLabel() {
        return label;
    }

}

với

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

Hoặc, tốt hơn, đặt giá trị enum thành khóa thuộc tính của gói tài nguyên được bản địa hóa (yêu cầu EL 3.0):

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

với cái này trong tệp thuộc tính được liên kết với gói tài nguyên #{text}

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

Một điều BalusC, là nó có thể "chọn" / xem trạng thái mà một câu hỏi có như mặc định (ví dụ như khi bạn đang chỉnh sửa một câu hỏi thì bạn đã thiết lập trạng thái của câu hỏi một cái gì đó)
Lucky Luke

Trong ví dụ trên, JSF sẽ làm điều đó theo mặc định khi #{bean.question.status}có giá trị enum hợp lệ. Bạn không cần phải làm bất cứ điều gì mong đợi để đảm bảo rằng thuộc questiontính trạng thái thích hợp được điền trước.
BalusC

@BalusC Làm cách nào để truy cập giá trị thứ tự từ JSF?
jacktrades

2
Nếu, giống như tôi, bạn nhận được một ngoại lệ định dạng số += status, thì hãy thử sử dụng .concat(status)như @Ziletka đề xuất.
whistling_marmot

Nếu bạn thích java.util.List, bạn chỉ có thể sửa đổi kiểu trả về getStatuses () thành List <Status> và trả về Arrays.asList (Status.values ​​());
stakahop

16

Để bản địa hóa, chúng tôi cũng có thể sử dụng giải pháp này:

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>

Vì vậy, đường dẫn tài nguyên cho các chuỗi bản địa hóa không được mã hóa cứng trong Enum.


1
Lưu ý rằng cú pháp này chỉ được hỗ trợ vì EL 2.2 là "tương đối" mới. Nếu không, bạn luôn có thể lấy <c:set>hoặc <ui:param>hoặc viết tắt một hàm EL tùy chỉnh.
BalusC

Cảm ơn bạn BalusC. Có thể bằng cách nào đó thay thế # {data.statuses} bằng Lớp enum mà không cần sử dụng đậu hỗ trợ (ví dụ: value = "# {org.myproject.Status.values}") không?
Ziletka

@BalusC bạn có chắc không? Tôi đang sử dụng GF 3.1.2 (Mojarra JSF 2.1.6).
Ziletka

4

Bạn có thể sử dụng <f:selectItems value="#{carBean.carList}" />và trả về danh sách các SelectItemtrường hợp bao bọc enum (sử dụng Status.values()để lấy tất cả các giá trị có thể có).


2

Bạn có thể sử dụng hàm el tiện ích sau để lấy các giá trị enum và sử dụng chúng trong một SelectOneMenuví dụ. Không cần phải tạo đậu và các phương pháp nấu bằng nồi hơi.

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

Đăng ký nó dưới dạng hàm el trong tệp 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>

Và cuối cùng gọi nó như:

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

Tương tự như câu trả lời BalusC, bạn nên sử dụng một gói tài nguyên với các nhãn enum được bản địa hóa và để mã rõ ràng hơn, bạn cũng có thể tạo một hàm như getEnumLabel(enum)


Không cần "hàm" (thêm phương thức), khi bạn có thể sử dụng #{myBundle[enumName.i18nKey]}và sau đó đặt các khóa i18n vào bảng liệt kê của mình dưới dạng thuộc tính: BLA_TYPE("SOME_BLA_TYPE_KEY")by BLA_TYPElà enum sẽ được sử dụng và SOME_BLA_TYPE_KEYlà khóa i18n.
Roland
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.