Akses nilai Enum menggunakan EL dengan JSTL

104

Saya memiliki Enum yang disebut Status yang didefinisikan sebagai berikut:

public enum Status { 

    VALID("valid"), OLD("old");

    private final String val;

    Status(String val) {
        this.val = val;
    }

    public String getStatus() {
        return val;
    }

}

Saya ingin mengakses nilai dari VALIDtag JSTL. Khususnya testatribut <c:when>tag. Misalnya

<c:when test="${dp.status eq Status.VALID">

Saya tidak yakin apakah ini mungkin.

IaCoder
sumber

Jawaban:

112

Perbandingan sederhana terhadap karya string:

<c:when test="${someModel.status == 'OLD'}">
Alexander Vasiljev
sumber
11
Bagi mereka yang membutuhkan sumber: Ini ditentukan (misalnya) di bagian 1.17 dari "Spesifikasi Bahasa Ekspresi, versi 2.2", yang merupakan bagian dari JSR-245 .
meriton
4
Spesifikasi JavaServer Pages ™, Versi 2.0 mengatakan di JSP.2.3.5.7: "• Jika A atau B adalah String yang memaksa A dan B ke String, bandingkan secara leksikal"
Roland Illig
11
Tetapi Anda kehilangan keuntungan dari memiliki enum: ini dapat menyebabkan kesalahpahaman yang rumit jika enum diubah suatu hari nanti. Biasanya, jika saya menemukan diri saya berubah enum, saya merasa cukup aman, dan mungkin aku tidak akan ingat bahwa string-to-enum-acuan dalam pandangan bahwa ...
reallynice
1
Apakah ini dibandingkan dengan toString dari enum? Jadi jika Anda menimpa toString (mis. Anda ingin nama tampilan yang bersahabat), maka Anda perlu memastikan bahwa Anda juga mengubah nilai yang dicocokkan.
Rupert Madden-Abbott
1
FWIW, hari ini di Java 8 saya (IBM Java untuk WebSphere, jika itu penting), ini sepertinya tidak berfungsi. Tampaknya hanya berfungsi jika dibandingkan dengan nilai string, yang di sini akan menjadi huruf kecil "lama"
dbreaux
54

Jika menggunakan Spring MVC, Spring Expression Language (SpEL) dapat membantu:

<spring:eval expression="dp.status == T(com.example.Status).VALID" var="isValid" />
<c:if test="${isValid}">
   isValid
</c:if>
James
sumber
1
Sepertinya ini tidak berfungsi untuk enum batin? Disebabkan oleh: org.springframework.expression.spel.SpelEvaluationException: EL1005E: (pos 0): Jenis tidak dapat ditemukan 'my.package.model.EngagementRequest.EngagementStatus'
Eddie
4
Coba gunakan 'my.package.model.EngagementRequest $ EngagementStatus'
James
Hal yang baik tentang solusi ini adalah Anda mendapatkan pesan kesalahan jika ada kesalahan dalam ekspresi Anda, yang tidak selalu terjadi dengan <c:if>dan <c:when>(gagal diam-diam).
vegemite4me
41

Anda memiliki 3 pilihan di sini, tidak ada yang sempurna:

  1. Anda dapat menggunakan scriptlet di testatribut:

    <c:when test="<%= dp.getStatus() == Status.VALID %>">

    Ini menggunakan enum, tetapi juga menggunakan scriptlet, yang bukan merupakan "cara yang benar" di JSP 2.0. Tapi yang paling penting, ini tidak bekerja ketika Anda ingin menambahkan kondisi lain untuk sama whenmenggunakan ${}. Dan ini berarti semua variabel yang ingin Anda uji harus dideklarasikan dalam scriptlet, atau disimpan dalam permintaan, atau sesi ( pageContextvariabel tidak tersedia dalam .tagfile).

  2. Anda dapat membandingkan dengan string:

    <c:when test="${dp.status == 'VALID'}">

    Ini terlihat bersih, tetapi Anda memperkenalkan string yang menduplikasi nilai enum dan tidak dapat divalidasi oleh kompilator. Jadi jika Anda menghapus nilai itu dari enum atau mengganti namanya, Anda tidak akan melihat bahwa bagian kode ini tidak dapat diakses lagi. Anda pada dasarnya harus melakukan pencarian / penggantian melalui kode setiap kali.

  3. Anda dapat menambahkan setiap nilai enum yang Anda gunakan ke dalam konteks halaman:

    <c:set var="VALID" value="<%=Status.VALID%>"/>

    dan kemudian Anda dapat melakukan ini:

    <c:when test="${dp.status == VALID}">

Saya lebih suka opsi terakhir (3), meskipun itu juga menggunakan scriptlet. Ini karena ini hanya menggunakannya saat Anda menyetel nilainya. Nanti Anda bisa menggunakannya dalam ekspresi EL yang lebih kompleks, bersama dengan kondisi EL lainnya. Sedangkan pada opsi (1) Anda tidak dapat menggunakan scriptlet dan ekspresi EL dalam testatribut whentag tunggal .

Matt
sumber
1
Mengenai opsi 2, kompilator tidak dapat memverifikasinya, tetapi pada saat runtime string akan diubah menjadi enum Enum.valueOf(Class<T> enumType, String name)yang akan memicu ELExceptionjika enum tidak memiliki konstanta dengan nama itu. Ungkapannya tidak akan selalu salah.
Mulai ulang
23

Jadi untuk menyelesaikan masalah saya sepenuhnya, saya perlu melakukan hal berikut:

<% pageContext.setAttribute("old", Status.OLD); %>

Kemudian saya bisa melakukan:

<c:when test="${someModel.status == old}"/>...</c:when>

yang bekerja seperti yang diharapkan.

IaCoder
sumber
12
menggunakan scriptlet adalah gaya yang buruk.
Eugene Retunsky
13

Berikut dua kemungkinan lagi:

Konstanta JSP EL 3.0

Selama Anda menggunakan setidaknya versi 3.0 dari EL, Anda dapat mengimpor konstanta ke halaman Anda sebagai berikut:

<%@ page import="org.example.Status" %>
<c:when test="${dp.status eq Status.VALID}">

Namun, beberapa IDE belum memahami hal ini (mis. IntelliJ ) sehingga Anda tidak akan mendapatkan peringatan jika salah ketik, hingga runtime.

Ini akan menjadi metode pilihan saya setelah mendapat dukungan IDE yang tepat.

Metode Pembantu

Anda bisa menambahkan getter ke enum Anda.

public enum Status { 
  VALID("valid"), OLD("old");

  private final String val;

  Status(String val) {
    this.val = val;
  }

  public String getStatus() {
    return val;
  }

  public boolean isValid() {
    return this == VALID;
  }

  public boolean isOld() {
    return this == OLD;
  }
}

Kemudian di JSP Anda:

<c:when test="${dp.status.valid}">

Ini didukung di semua IDE dan juga akan berfungsi jika Anda belum dapat menggunakan EL 3.0. Inilah yang saya lakukan saat ini karena itu membuat semua logika tetap terbungkus dalam enum saya.

Juga berhati-hatilah jika memungkinkan untuk variabel yang menyimpan enum menjadi null. Anda perlu memeriksanya terlebih dahulu jika kode Anda tidak menjamin bahwa itu bukan null:

<c:when test="${not empty db.status and dp.status.valid}">

Saya pikir metode ini lebih unggul daripada metode di mana Anda menetapkan nilai perantara di JSP karena Anda harus melakukannya di setiap halaman di mana Anda perlu menggunakan enum. Namun, dengan solusi ini Anda hanya perlu mendeklarasikan pengambil satu kali.

Rupert Madden-Abbott
sumber
2
Bagian "JSP EL 3.0 Constants" harus menjadi jawaban yang diterima karena ini adalah cara standar untuk mencapai hasil yang diperlukan menggunakan fungsionalitas bawaan. Di samping catatan, InteliJ IDEA (setidaknya versi Ultimate 2017.2.4) mendukungnya di luar kotak dan menunjukkan daftar konstanta yang tersedia saat Anda mengetik ${MyEnum.}, beri tanda sisipan tepat setelah titik dan tekan Ctrl+Spaceuntuk menampilkan saran.
izogfif
[ UPDATE ] Sepertinya IntelliJ IDEA sudah memperbaiki masalah yang disebutkan dalam jawaban ini.
informatik01
10

Untuk tujuan ini saya melakukan hal berikut:

<c:set var="abc">
    <%=Status.OLD.getStatus()%>
</c:set>

<c:if test="${someVariable == abc}">
    ....
</c:if>

Ini terlihat jelek, tapi berhasil!

Xtreme Biker
sumber
3

Saya tidak punya jawaban untuk pertanyaan Kornel, tapi saya punya komentar tentang contoh skrip lainnya. Sebagian besar ekspresi percaya secara implisit pada toString(), tetapi Enum.valueOf()mengharapkan nilai yang berasal dari / cocok dengan Enum.name()properti. Jadi seseorang harus menggunakan mis:

<% pageContext.setAttribute("Status_OLD", Status.OLD.name()); %>
...
<c:when test="${someModel.status == Status_OLD}"/>...</c:when>
eremmel
sumber
2

Tambahkan metode ke enum seperti:

public String getString() {
    return this.name();
}

Sebagai contoh

public enum MyEnum {
    VALUE_1,
    VALUE_2;
    public String getString() {
        return this.name();
    }
}

Kemudian Anda dapat menggunakan:

<c:if test="${myObject.myEnumProperty.string eq 'VALUE_2'}">...</c:if>
Dekan
sumber
1

Saat menggunakan kerangka MVC saya meletakkan yang berikut ini di pengontrol saya.

request.setAttribute(RequestParameterNamesEnum.INBOX_ACTION.name(), RequestParameterNamesEnum.INBOX_ACTION.name());

Ini memungkinkan saya untuk menggunakan berikut ini di Halaman JSP saya.

<script> var url = 'http://www.nowhere.com/?${INBOX_ACTION}=' + someValue;</script>

Ini juga dapat digunakan dalam perbandingan Anda

<c:when test="${someModel.action == INBOX_ACTION}">

Yang saya lebih suka daripada memasukkan string literal.

ElectronicBlacksmith
sumber
1
<%@ page import="com.example.Status" %>

1. ${dp.status eq Title.VALID.getStatus()}
2. ${dp.status eq Title.VALID}
3. ${dp.status eq Title.VALID.toString()}
  • Letakkan impor di bagian atas , di header halaman JSP
  • Jika Anda ingin bekerja dengan metode getStatus , gunakan # 1
  • Jika Anda ingin bekerja dengan elemen enum itu sendiri, gunakan # 2 atau # 3
  • Anda dapat menggunakan ==, bukan eq
Mehdi
sumber
-1

Saya biasanya menganggap itu praktik yang buruk untuk mencampur kode java ke dalam file jsps / tag. Menggunakan 'eq' seharusnya berhasil:

<c:if test="${dp.Status eq 'OLD'}">
  ...
</c:if>
Eclatante
sumber
3
Jadi ini adalah praktik yang buruk untuk digunakan, ==bukan eq? Mereka melakukan keduanya persis sama, jadi tidak ada cara "trik".
BalusC
Tentu saja, saya tidak membuat pernyataan tentang penggunaan eq vs ==. Banyak jawaban untuk pertanyaan ini melibatkan memasukkan kode java ke dalam file jsp atau tag yang dapat menjadi penopang. Saya lebih suka menjaga logika bisnis dalam kode java (di mana unit dapat diuji dengan mudah dan menyeluruh) terpisah dari logika tampilan di JSP.
Eclatante
7
Bagi saya, tampaknya praktik yang sama buruknya untuk memasukkan string ajaib ke dalam JSP Anda yang tidak dapat diperiksa oleh kompiler saat Anda ingin memfaktorkan ulang enum Anda. Sepertinya tidak ada solusi yang baik untuk ini di kedua sisi.
Lyle
-1

Saya melakukannya dengan cara ini ketika ada banyak poin untuk digunakan ...

public enum Status { 

    VALID("valid"), OLD("old");

    private final String val;

    Status(String val) {
        this.val = val;
    }

    public String getStatus() {
        return val;
    }

    public static void setRequestAttributes(HttpServletRequest request) {
        Map<String,String> vals = new HashMap<String,String>();
        for (Status val : Status.values()) {
            vals.put(val.name(), val.value);
        }
        request.setAttribute("Status", vals);
    }

}

JSP

<%@ page import="...Status" %>
<% Status.setRequestAttributes(request) %>

<c:when test="${dp.status eq Status.VALID}">
...
HS Shin
sumber
-2

Di Kelas Java:

    public class EnumTest{
    //Other property link
    private String name;
    ....

        public enum Status {
                ACTIVE,NEWLINK, BROADCASTED, PENDING, CLICKED, VERIFIED, AWARDED, INACTIVE, EXPIRED, DELETED_BY_ADMIN;
            }

        private Status statusobj ;

    //Getter and Setters
}

Jadi sekarang POJO dan enum obj dibuat. Sekarang EnumTest Anda akan mengatur objek sesi menggunakan di servlet atau kelas controller session.setAttribute ("enumTest", EnumTest);

Di Halaman JSP

<c:if test="${enumTest.statusobj == 'ACTIVE'}">

//TRUE??? THEN PROCESS SOME LOGIC
Pavan
sumber