Accedi al valore Enum utilizzando EL con JSTL


104

Ho un Enum chiamato Status definito come tale:

public enum Status { 

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

    private final String val;

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

    public String getStatus() {
        return val;
    }

}

Vorrei accedere al valore di VALIDda un tag JSTL. Nello specifico l' testattributo del <c:when>tag. Per esempio

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

Non sono sicuro che sia possibile.

Risposte:


112

Un semplice confronto con le stringhe funziona:

<c:when test="${someModel.status == 'OLD'}">

11
Per coloro che richiedono una fonte: Ciò è specificato (ad esempio) nella sezione 1.17 della "Specifica del linguaggio di espressione, versione 2.2", che fa parte di JSR-245 .
meriton

4
La specifica JavaServer Pages ™, versione 2.0 dice in JSP.2.3.5.7: "• Se A o B è String costringe sia A che B a String, confronta lessicalmente"
Roland Illig

11
Ma perdi il vantaggio di avere un enum: questo potrebbe portare a ingombranti incomprensioni se un giorno l'enum dovesse cambiare. Di solito, se mi trovo a cambiare un enum, mi sento abbastanza al sicuro, e probabilmente non ricorderei quel riferimento da stringa a enum in quella vista ...
really nice

1
È questo il confronto con toString dell'enumerazione? Quindi, se si sovrascrive toString (ad esempio, si desidera un nome visualizzato descrittivo), è necessario assicurarsi di modificare anche il valore rispetto al quale viene confrontato.
Rupert Madden-Abbott

1
FWIW, oggi sul mio Java 8 (IBM Java per WebSphere, nel caso sia importante), questo non sembra funzionare. Sembra funzionare solo se confrontato con il valore della stringa, che qui sarebbe "vecchio"
minuscolo

54

Se si utilizza Spring MVC, Spring Expression Language (SpEL) può essere utile:

<spring:eval expression="dp.status == T(com.example.Status).VALID" var="isValid" />
<c:if test="${isValid}">
   isValid
</c:if>

1
Sembra che questo non funzioni per enumerazioni interne? Causato da: org.springframework.expression.spel.SpelEvaluationException: EL1005E: (pos 0): Impossibile trovare il tipo "my.package.model.EngagementRequest.EngagementStatus"
Eddie

4
Prova a utilizzare "my.package.model.EngagementRequest $ EngagementStatus"
James

Un aspetto positivo di questa soluzione è che ricevi un messaggio di errore se c'è un errore nella tua espressione, cosa che non sempre accade con <c:if>e <c:when>(falliscono silenziosamente).
vegemite4me

41

Hai 3 scelte qui, nessuna delle quali è perfetta:

  1. Puoi utilizzare uno scriptlet testnell'attributo:

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

    Questo utilizza l'enum, ma utilizza anche uno scriptlet, che non è il "modo giusto" in JSP 2.0. Ma soprattutto, questo non funziona quando si desidera aggiungere un'altra condizione allo stesso whenutilizzo ${}. E questo significa che tutte le variabili che vuoi testare devono essere dichiarate in uno scriptlet, o mantenute in richiesta o sessione (la pageContextvariabile non è disponibile nei .tagfile).

  2. Puoi confrontare con la stringa:

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

    Sembra pulito, ma stai introducendo una stringa che duplica il valore enum e non può essere convalidato dal compilatore. Quindi, se rimuovi quel valore dall'enumerazione o lo rinomini, non vedrai che questa parte di codice non è più accessibile. Fondamentalmente devi fare una ricerca / sostituzione attraverso il codice ogni volta.

  3. Puoi aggiungere ciascuno dei valori enum che utilizzi nel contesto della pagina:

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

    e poi puoi farlo:

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

Preferisco l'ultima opzione (3), anche se utilizza anche uno scriptlet. Questo perché lo utilizza solo quando imposti il ​​valore. Successivamente è possibile utilizzarlo in espressioni EL più complesse, insieme ad altre condizioni EL. Mentre nell'opzione (1) non è possibile utilizzare uno scriptlet e un'espressione EL testnell'attributo di un singolo whentag.


1
Per quanto riguarda l'opzione 2, il compilatore non può verificarla, ma in fase di esecuzione la stringa verrà convertita in un enum utilizzando il Enum.valueOf(Class<T> enumType, String name)quale attiverà un ELExceptionse l'enum non ha una costante con quel nome. L'espressione non sarà sempre falsa.
Riavvia il

23

Quindi, per risolvere completamente il mio problema, dovevo fare quanto segue:

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

Poi sono stato in grado di fare:

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

che ha funzionato come previsto.


12
l'uso di scriptlet è di cattivo gusto.
Eugene Retunsky

13

Ecco altre due possibilità:

Costanti JSP EL 3.0

Finché utilizzi almeno la versione 3.0 di EL, puoi importare le costanti nella tua pagina come segue:

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

Tuttavia, alcuni IDE non lo capiscono ancora (ad esempio IntelliJ ) quindi non riceverai alcun avviso se fai un errore di battitura, fino al runtime.

Questo sarebbe il mio metodo preferito una volta ottenuto il supporto IDE appropriato.

Metodi di aiuto

Potresti semplicemente aggiungere getter al tuo enum.

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

Quindi nel tuo JSP:

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

Questo è supportato in tutti gli IDE e funzionerà anche se non puoi ancora usare EL 3.0. Questo è quello che faccio al momento perché mantiene tutta la logica racchiusa nel mio enum.

Fai anche attenzione se è possibile che la variabile che memorizza l'enum sia nulla. Dovresti prima verificarlo se il tuo codice non garantisce che non sia nullo:

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

Penso che questo metodo sia superiore a quelli in cui imposti un valore intermedio nel JSP perché devi farlo in ogni pagina in cui devi usare l'enumerazione. Tuttavia, con questa soluzione è necessario dichiarare il getter una sola volta.


2
La parte "JSP EL 3.0 Costanti" deve essere la risposta accettata poiché è il modo standard per ottenere il risultato richiesto utilizzando la funzionalità incorporata. Come nota a margine, InteliJ IDEA (almeno versione Ultimate 2017.2.4) lo supporta immediatamente e mostra l'elenco delle costanti disponibili quando digiti ${MyEnum.}, metti il ​​cursore subito dopo il punto e premi Ctrl+Spaceper mostrare i suggerimenti.
izogfif

[ AGGIORNAMENTO ] Sembra che IntelliJ IDEA abbia già risolto il problema menzionato in questa risposta.
informatik01

10

A tal fine, faccio quanto segue:

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

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

Sembra brutto, ma funziona!


3

Non ho una risposta alla domanda di Kornel, ma ho un'osservazione sugli altri esempi di script. La maggior parte delle espressioni si fida implicitamente di toString(), ma si Enum.valueOf()aspetta un valore che proviene da / corrisponde alla Enum.name()proprietà. Quindi si dovrebbe usare ad esempio:

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

2

Aggiungi un metodo all'enumerazione come:

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

Per esempio

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

Quindi puoi usare:

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

1

Quando si utilizza un framework MVC, inserisco quanto segue nel mio controller.

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

Ciò mi consente di utilizzare quanto segue nella mia pagina JSP.

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

Può anche essere utilizzato nel tuo confronto

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

Che preferisco piuttosto che inserire una stringa letterale.


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()}
  • Metti l'importazione in alto , nell'intestazione della pagina JSP
  • Se vuoi lavorare con il metodo getStatus , usa # 1
  • Se vuoi lavorare con l' elemento enum stesso, usa # 2 o # 3
  • Puoi usare == invece di eq

-1

Generalmente considero una cattiva pratica mescolare codice Java in file jsps / tag. Usare 'eq' dovrebbe fare il trucco:

<c:if test="${dp.Status eq 'OLD'}">
  ...
</c:if>

3
Quindi è una cattiva pratica da usare al ==posto di eq? Fanno entrambi esattamente lo stesso, quindi non c'è modo di "trucco".
BalusC

Ovviamente, non stavo facendo una dichiarazione sull'uso di eq vs ==. Molte risposte a questa domanda hanno comportato l'inserimento di codice java in file jsp o tag che possono essere una stampella. Preferisco mantenere la logica di business nel codice java (dove può essere testato facilmente e completamente) separata dalla logica di visualizzazione nel JSP.
Eclatante

7
A me sembra altrettanto pessima pratica inserire stringhe magiche nel tuo JSP che non possono essere controllate dal compilatore quando vuoi refactoring delle tue enumerazioni. Sembra che non ci sia una buona soluzione a questo su entrambi i lati.
Lyle

-1

Lo faccio in questo modo quando ci sono molti punti da usare ...

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}">
...

-2

Nella classe 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
}

Quindi ora vengono creati POJO ed enum obj. Ora EnumTest verrà impostato nell'oggetto sessione utilizzando nel servlet o nella classe controller session.setAttribute ("enumTest", EnumTest);

Nella pagina JSP

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

//TRUE??? THEN PROCESS SOME LOGIC
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.