วิธีใช้ค่า enum ใน f: selectItem (s)


103

ฉันต้องการสร้างเมนูแบบเลื่อนลง selectOneMenu เพื่อที่ฉันจะได้เลือกสถานะสำหรับคำถามของฉัน เป็นไปได้หรือไม่ที่จะทำให้ f: selectItem มีความยืดหยุ่นมากขึ้นโดยพิจารณาว่าจะเกิดอะไรขึ้นหากลำดับของ enums เปลี่ยนไปและรายการมีขนาดใหญ่หรือไม่? และฉันจะทำได้ดีกว่านี้ไหม และเป็นไปได้หรือไม่ที่จะ "เลือก" รายการที่มีคำถาม?

คลาส 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>

หากคุณตั้งใจจะควบคุมป้ายกำกับด้วยเช่นกันคุณสามารถเพิ่มลงใน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;
    }

}

ด้วย

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

หรือที่ดีกว่าคือทำให้ค่า enum เป็นคีย์คุณสมบัติของบันเดิลทรัพยากรที่แปลเป็นภาษาท้องถิ่น (ต้องใช้ 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}มีค่า enum ที่ถูกต้อง คุณไม่จำเป็นต้องทำอะไรโดยคาดหวังว่าquestionจะได้รับคุณสมบัติสถานะที่เหมาะสมไว้ล่วงหน้า
BalusC

@BalusC จะเข้าถึงค่าลำดับจาก JSF ได้อย่างไร?
jacktrades

2
ถ้าเช่นฉันคุณได้รับข้อยกเว้นรูปแบบตัวเลขให้+= statusลองใช้.concat(status)ตามที่ @Ziletka แนะนำ
whistling_marmot

หากคุณต้องการ java.util.List คุณก็สามารถแก้ไข getStatuses () return type เป็น 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>หรือ homebrew ฟังก์ชัน EL ที่กำหนดเองได้ตลอดเวลา
BalusC

ขอบคุณ BalusC. เป็นไปได้ไหมที่จะแทนที่ # {data.statuses} ด้วย enum Class โดยไม่ใช้ backing bean (เช่น value = "# {org.myproject.Status.values}")
sasynkamil

@BalusC แน่ใจเหรอ? ฉันใช้ GF 3.1.2 (Mojarra JSF 2.1.6)
sasynkamil

4

คุณสามารถใช้ <f:selectItems value="#{carBean.carList}" />และส่งคืนรายการของSelectItemอินสแตนซ์ที่รวม enum (ใช้Status.values()เพื่อรับค่าที่เป็นไปได้ทั้งหมด)


2

คุณสามารถใช้ฟังก์ชัน el ยูทิลิตี้ต่อไปนี้เพื่อรับค่า enum และใช้ใน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 คุณควรใช้ชุดทรัพยากรที่มีป้ายกำกับ enum ที่แปลเป็นภาษาท้องถิ่นและสำหรับรหัสที่สะอาดยิ่งขึ้นคุณยังสามารถสร้างฟังก์ชันเช่น getEnumLabel(enum)


ไม่จำเป็นต้องมี "ฟังก์ชัน" (วิธีการเพิ่มเติม) เมื่อคุณสามารถใช้#{myBundle[enumName.i18nKey]}แล้วใส่คีย์ i18n ในการแจงนับของคุณเป็นคุณสมบัติ: BLA_TYPE("SOME_BLA_TYPE_KEY")โดยBLA_TYPEคือ enum ที่จะใช้และSOME_BLA_TYPE_KEYเป็นคีย์ i18n
Roland
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.