Greifen Sie mit EL mit JSTL auf den Enum-Wert zu

104

Ich habe eine Aufzählung namens Status als solche definiert:

public enum Status { 

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

    private final String val;

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

    public String getStatus() {
        return val;
    }

}

Ich möchte über VALIDeinen JSTL-Tag auf den Wert von zugreifen . Insbesondere das testAttribut des <c:when>Tags. Z.B

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

Ich bin mir nicht sicher, ob das möglich ist.

IaCoder
quelle

Antworten:

112

Ein einfacher Vergleich mit String funktioniert:

<c:when test="${someModel.status == 'OLD'}">
Alexander Vasiljev
quelle
11
Für diejenigen, die eine Quelle benötigen: Dies wird (zum Beispiel) in Abschnitt 1.17 der "Expression Language Specification, Version 2.2" angegeben, die Teil von JSR-245 ist .
Meriton
4
In der JavaServer Pages ™ -Spezifikation, Version 2.0, heißt es in JSP.2.3.5.7: "• Wenn A oder B String sind, zwingen Sie sowohl A als auch B zu String, vergleichen Sie lexikalisch"
Roland Illig
11
Sie verlieren jedoch den Vorteil einer Aufzählung: Dies kann zu umständlichen Missverständnissen führen, wenn die Aufzählung eines Tages geändert wird. Wenn ich eine Aufzählung ändere, fühle ich mich normalerweise ziemlich sicher, und wahrscheinlich würde ich mich in dieser Ansicht nicht an diese Referenz von Zeichenfolge zu Aufzählung erinnern ...
wirklich schön,
1
Ist dies ein Vergleich mit dem toString der Aufzählung? Wenn Sie also den toString überschreiben (z. B. einen Anzeigenamen möchten), müssen Sie sicherstellen, dass Sie auch den Wert ändern, mit dem abgeglichen wird.
Rupert Madden-Abbott
1
FWIW, heute auf meinem Java 8 (IBM Java für WebSphere, falls es darauf ankommt) scheint dies nicht zu funktionieren. Es scheint nur zu funktionieren, wenn man es mit dem String-Wert vergleicht, der hier in Kleinbuchstaben "alt" wäre
dbreaux
54

Bei Verwendung von Spring MVC kann die Spring Expression Language (SpEL) hilfreich sein:

<spring:eval expression="dp.status == T(com.example.Status).VALID" var="isValid" />
<c:if test="${isValid}">
   isValid
</c:if>
James
quelle
1
Scheint das nicht für innere Aufzählungen zu funktionieren? Auslöser: org.springframework.expression.spel.SpelEvaluationException: EL1005E: (pos 0): Typ 'my.package.model.EngagementRequest.EngagementStatus'
Eddie
4
Versuchen Sie, 'my.package.model.EngagementRequest $ EngagementStatus' zu verwenden
James
Eine gute Sache bei dieser Lösung ist, dass Sie eine Fehlermeldung erhalten, wenn ein Fehler in Ihrem Ausdruck vorliegt, der nicht immer mit <c:if>und <c:when>auftritt (sie schlagen leise fehl).
vegemite4me
41

Sie haben hier drei Möglichkeiten, von denen keine perfekt ist:

  1. Sie können ein Scriptlet im testAttribut verwenden:

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

    Dies verwendet die Aufzählung, aber es wird auch ein Scriptlet verwendet, was in JSP 2.0 nicht der "richtige Weg" ist. Am wichtigsten ist jedoch, dass dies nicht funktioniert, wenn Sie derselben whenVerwendung eine weitere Bedingung hinzufügen möchten ${}. Dies bedeutet, dass alle Variablen, die Sie testen möchten, in einem Scriptlet deklariert oder in einer Anfrage oder Sitzung aufbewahrt werden müssen ( pageContextVariable ist in .tagDateien nicht verfügbar ).

  2. Sie können mit Zeichenfolge vergleichen:

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

    Das sieht sauber aus, aber Sie führen eine Zeichenfolge ein, die den Aufzählungswert dupliziert und vom Compiler nicht überprüft werden kann. Wenn Sie diesen Wert aus der Aufzählung entfernen oder umbenennen, sehen Sie nicht, dass auf diesen Teil des Codes nicht mehr zugegriffen werden kann. Grundsätzlich müssen Sie den Code jedes Mal durchsuchen / ersetzen.

  3. Sie können jeden der von Ihnen verwendeten Aufzählungswerte zum Seitenkontext hinzufügen:

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

    und dann können Sie dies tun:

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

Ich bevorzuge die letzte Option (3), obwohl sie auch ein Scriptlet verwendet. Dies liegt daran, dass es nur verwendet wird, wenn Sie den Wert festlegen. Später können Sie es in komplexeren EL-Ausdrücken zusammen mit anderen EL-Bedingungen verwenden. In Option (1) können Sie kein Scriptlet und keinen EL-Ausdruck im testAttribut eines einzelnen whenTags verwenden.

Matt
quelle
1
In Bezug auf Option 2 kann der Compiler dies nicht überprüfen, aber zur Laufzeit wird die Zeichenfolge in eine Aufzählung konvertiert, mit Enum.valueOf(Class<T> enumType, String name)der eine ausgelöst wird, ELExceptionwenn die Aufzählung keine Konstante mit diesem Namen hat. Der Ausdruck wird nicht immer falsch sein.
Starten Sie den
23

Um mein Problem vollständig zu lösen, musste ich Folgendes tun:

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

Dann konnte ich tun:

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

das hat wie erwartet funktioniert.

IaCoder
quelle
12
Die Verwendung von Scriptlets ist ein schlechter Stil.
Eugene Retunsky
13

Hier sind zwei weitere Möglichkeiten:

JSP EL 3.0-Konstanten

Solange Sie mindestens Version 3.0 von EL verwenden, können Sie Konstanten wie folgt in Ihre Seite importieren:

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

Einige IDEs verstehen dies jedoch noch nicht (z. B. IntelliJ ), sodass Sie bis zur Laufzeit keine Warnungen erhalten, wenn Sie einen Tippfehler machen.

Dies wäre meine bevorzugte Methode, sobald sie die richtige IDE-Unterstützung erhält.

Hilfsmethoden

Sie können Ihrer Aufzählung einfach Getter hinzufügen.

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

Dann in Ihrer JSP:

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

Dies wird in allen IDEs unterstützt und funktioniert auch, wenn Sie EL 3.0 noch nicht verwenden können. Dies ist, was ich im Moment mache, weil es die gesamte Logik in meiner Aufzählung festhält.

Seien Sie auch vorsichtig, wenn es möglich ist, dass die Variable, in der die Aufzählung gespeichert ist, null ist. Sie müssten dies zuerst überprüfen, wenn Ihr Code nicht garantiert, dass er nicht null ist:

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

Ich denke, diese Methode ist denen überlegen, bei denen Sie einen Zwischenwert in der JSP festlegen, da Sie dies auf jeder Seite tun müssen, auf der Sie die Aufzählung verwenden müssen. Bei dieser Lösung müssen Sie den Getter jedoch nur einmal deklarieren.

Rupert Madden-Abbott
quelle
2
Der Teil "JSP EL 3.0-Konstanten" muss die akzeptierte Antwort sein, da dies die Standardmethode ist, um das erforderliche Ergebnis mithilfe der integrierten Funktionalität zu erzielen. Nebenbei bemerkt, InteliJ IDEA (mindestens Ultimate Version 2017.2.4) unterstützt dies sofort und zeigt eine Liste der verfügbaren Konstanten an, wenn Sie tippen ${MyEnum.}, Caret direkt nach Punkt setzen und drücken Ctrl+Space, um Vorschläge anzuzeigen .
izogfif
[ UPDATE ] IntelliJ IDEA scheint das in dieser Antwort erwähnte Problem bereits behoben zu haben.
informatik01
10

Zu diesem Zweck mache ich Folgendes:

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

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

Es sieht hässlich aus, funktioniert aber!

Xtreme Biker
quelle
3

Ich habe keine Antwort auf die Frage von Kornel, aber ich habe eine Bemerkung zu den anderen Skriptbeispielen. Der größte Teil des Ausdrucks vertraut implizit auf die toString(), Enum.valueOf()erwartet jedoch einen Wert, der von der Enum.name()Eigenschaft stammt / mit dieser übereinstimmt . Also sollte man zB verwenden:

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

Fügen Sie der Aufzählung eine Methode hinzu, wie:

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

Beispielsweise

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

Dann können Sie verwenden:

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

Bei Verwendung eines MVC-Frameworks habe ich Folgendes in meinen Controller eingefügt.

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

Dadurch kann ich Folgendes auf meiner JSP-Seite verwenden.

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

Es kann auch in Ihrem Vergleich verwendet werden

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

Was ich lieber als ein String-Literal eingebe.

ElectronicBlacksmith
quelle
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()}
  • Fügen Sie den Import oben in den JSP-Seitenkopf ein
  • Wenn Sie mit der Methode getStatus arbeiten möchten , verwenden Sie # 1
  • Wenn Sie mit dem enum-Element selbst arbeiten möchten , verwenden Sie entweder # 2 oder # 3
  • Sie können == anstelle von Gl
Mehdi
quelle
-1

Ich halte es im Allgemeinen für eine schlechte Praxis, Java-Code in jsps / tag-Dateien zu mischen. Die Verwendung von 'eq' sollte den Trick machen:

<c:if test="${dp.Status eq 'OLD'}">
  ...
</c:if>
Eclatante
quelle
3
Es ist also eine schlechte Praxis, ==statt zu verwenden eq? Sie machen beide genau das gleiche, also gibt es keine Möglichkeit für einen "Trick".
BalusC
Natürlich habe ich keine Aussage zur Verwendung von eq vs == gemacht. Viele Antworten auf diese Frage beinhalteten das Einfügen von Java-Code in JSP- oder Tag-Dateien, die eine Krücke sein können. Ich bevorzuge es, die Geschäftslogik im Java-Code (wo sie einfach und gründlich getestet werden kann) von der Anzeigelogik in der JSP zu trennen.
Eclatante
7
Für mich scheint es eine ebenso schlechte Praxis zu sein, magische Zeichenfolgen in Ihre JSP einzufügen, die vom Compiler nicht überprüft werden können, wenn Sie Ihre Aufzählungen umgestalten möchten. Es scheint, als gäbe es auf beiden Seiten keine gute Lösung dafür.
Lyle
-1

Ich mache es so, wenn es viele Punkte gibt ...

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
quelle
-2

In der Java-Klasse:

    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
}

Nun werden POJO und enum obj erstellt. Jetzt legen Sie EnumTest im Sitzungsobjekt fest, indem Sie in der Servlet- oder Controller-Klasse session.setAttribute ("enumTest", EnumTest) verwenden.

In der JSP-Seite

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

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