Uzyskaj dostęp do wartości wyliczenia przy użyciu EL z JSTL

104

Mam Enum o nazwie Status zdefiniowany jako:

public enum Status { 

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

    private final String val;

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

    public String getStatus() {
        return val;
    }

}

Chciałbym uzyskać dostęp do wartości VALIDz tagu JSTL. W szczególności testatrybut <c:when>tagu. Na przykład

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

Nie jestem pewien, czy jest to możliwe.

IaCoder
źródło

Odpowiedzi:

112

Proste porównanie ze stringiem działa:

<c:when test="${someModel.status == 'OLD'}">
Alexander Vasiljev
źródło
11
Dla potrzebujących źródła: jest to określone (na przykład) w sekcji 1.17 „Specyfikacji języka wyrażeń, wersja 2.2”, która jest częścią JSR-245 .
meriton
4
Specyfikacja JavaServer Pages ™, wersja 2.0, mówi w JSP.2.3.5.7: „• Jeśli A lub B to String wymusza zarówno A, jak i B na String, porównaj leksykalnie”
Roland Illig
11
Ale tracisz korzyść z posiadania wyliczenia: może to prowadzić do kłopotliwych nieporozumień, jeśli wyliczenie zostanie zmienione pewnego dnia. Zwykle, jeśli znajdę się zmienia enum, czuję się dość bezpiecznie, i prawdopodobnie nie będę pamiętać, że string-to-enum odniesienie w tym widoku ...
reallynice
1
Czy jest to porównanie z toString wyliczenia? Więc jeśli nadpisujesz toString (np. Chcesz mieć przyjazną nazwę wyświetlaną), musisz upewnić się, że zmienisz również wartość, do której jest dopasowywana.
Rupert Madden-Abbott
1
FWIW, dziś na mojej Javie 8 (IBM Java for WebSphere, na wypadek, gdyby miało to znaczenie), to nie działa. Wydaje się, że działa tylko wtedy, gdy porównuje się z wartością ciągu, która w tym przypadku byłaby małą literą „stara”
dbreaux
54

W przypadku korzystania ze Spring MVC pomocny może być język Spring Expression Language (SpEL):

<spring:eval expression="dp.status == T(com.example.Status).VALID" var="isValid" />
<c:if test="${isValid}">
   isValid
</c:if>
James
źródło
1
Wydaje się, że to nie działa w przypadku wewnętrznych wyliczeń? Przyczyna: org.springframework.expression.spel.SpelEvaluationException: EL1005E: (pozycja 0): nie można znaleźć typu „my.package.model.EngagementRequest.EngagementStatus”
Eddie
4
Spróbuj użyć „my.package.model.EngagementRequest $ EngagementStatus”
James
Dobrą rzeczą w tym rozwiązaniu jest to, że otrzymujesz komunikat o błędzie, jeśli w twoim wyrażeniu jest błąd, co nie zawsze ma miejsce w przypadku <c:if>i <c:when>(po cichu zawodzą).
vegemite4me
41

Masz tutaj 3 możliwości, z których żadna nie jest idealna:

  1. Możesz użyć skryptletu w testatrybucie:

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

    Używa to wyliczenia, ale także skryptletu, co nie jest „właściwą drogą” w JSP 2.0. Ale co najważniejsze, nie działa to, gdy chcesz dodać kolejny warunek do tego samego whenużycia ${}. A to oznacza, że ​​wszystkie zmienne, które chcesz przetestować, muszą być zadeklarowane w skrypcie, przechowywane w żądaniu lub sesji ( pageContextzmienna nie jest dostępna w .tagplikach).

  2. Możesz porównać ze stringiem:

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

    Wygląda to na czysty, ale wprowadzasz ciąg, który duplikuje wartość wyliczenia i nie może zostać zweryfikowany przez kompilator. Więc jeśli usuniesz tę wartość z wyliczenia lub zmienisz jej nazwę, nie zobaczysz, że ta część kodu nie jest już dostępna. Zasadniczo za każdym razem musisz wyszukiwać / zastępować kod.

  3. Możesz dodać każdą z używanych wartości wyliczenia do kontekstu strony:

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

    a następnie możesz to zrobić:

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

Wolę ostatnią opcję (3), mimo że również używa skryptletu. Dzieje się tak, ponieważ używa go tylko podczas ustawiania wartości. Później możesz go używać w bardziej złożonych wyrażeniach EL, razem z innymi warunkami EL. W opcji (1) nie możesz używać skryptletu i wyrażenia EL w testatrybucie pojedynczego whenznacznika.

Matt
źródło
1
Jeśli chodzi o opcję 2, kompilator nie może jej zweryfikować, ale w czasie wykonywania ciąg zostanie przekonwertowany na wyliczenie przy użyciu, Enum.valueOf(Class<T> enumType, String name)co spowoduje wyzwolenie, ELExceptionjeśli wyliczenie nie ma stałej o tej nazwie. Wyrażenie nie zawsze będzie fałszywe.
Zrestartuj
23

Aby w pełni rozwiązać problem, musiałem wykonać następujące czynności:

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

Wtedy mogłem zrobić:

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

który działał zgodnie z oczekiwaniami.

IaCoder
źródło
12
używanie skryptletów to zły styl.
Eugene Retunsky
13

Oto dwie dodatkowe możliwości:

Stałe JSP EL 3.0

Jeśli używasz co najmniej wersji 3.0 EL, możesz importować stałe do swojej strony w następujący sposób:

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

Jednak niektóre IDE jeszcze tego nie rozumieją (np. IntelliJ ), więc nie otrzymasz żadnych ostrzeżeń, jeśli popełnisz literówkę, aż do czasu uruchomienia.

To byłaby moja preferowana metoda, gdy uzyska odpowiednią obsługę IDE.

Metody pomocnicze

Możesz po prostu dodać metody pobierające do swojego wyliczenia.

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

Następnie w Twoim JSP:

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

Jest to obsługiwane we wszystkich IDE i będzie działać również, jeśli nie możesz jeszcze używać EL 3.0. To właśnie robię w tej chwili, ponieważ utrzymuje całą logikę zawiniętą w moim wyliczeniu.

Uważaj także, jeśli zmienna przechowująca wyliczenie może mieć wartość null. Najpierw musisz to sprawdzić, jeśli twój kod nie gwarantuje, że nie jest pusty:

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

Myślę, że ta metoda jest lepsza od tych, w których ustawiasz wartość pośrednią na stronie JSP, ponieważ musisz to zrobić na każdej stronie, na której musisz użyć wyliczenia. Jednak w przypadku tego rozwiązania wystarczy tylko raz zadeklarować getter.

Rupert Madden-Abbott
źródło
2
Część „Stałe JSP EL 3.0” musi być akceptowaną odpowiedzią, ponieważ jest to standardowy sposób osiągnięcia wymaganego wyniku przy użyciu wbudowanych funkcji. Na marginesie, InteliJ IDEA (przynajmniej wersja Ultimate 2017.2.4) obsługuje go po wyjęciu z pudełka i wyświetla listę dostępnych stałych podczas pisania ${MyEnum.}, umieść kursor tuż po kropce i naciśnij, Ctrl+Spaceaby wyświetlić sugestie.
izogfif
[ AKTUALIZACJA ] Wygląda na to, że IntelliJ IDEA już naprawił problem wymieniony w tej odpowiedzi.
informatik01
10

W tym celu wykonuję następujące czynności:

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

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

Wygląda brzydko, ale działa!

Xtreme Biker
źródło
3

Nie mam odpowiedzi na pytanie Kornela, ale mam uwagę na temat innych przykładów skryptów. Większość wyrażeń ufa niejawnie do toString(), ale Enum.valueOf()oczekuje wartości, która pochodzi z / pasuje do Enum.name()właściwości. Należy więc użyć np .:

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

Dodaj metodę do wyliczenia, na przykład:

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

Na przykład

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

Następnie możesz użyć:

<c:if test="${myObject.myEnumProperty.string eq 'VALUE_2'}">...</c:if>
Dziekan
źródło
1

Korzystając z frameworka MVC, umieszczam w moim kontrolerze.

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

Dzięki temu mogę używać następujących elementów na mojej stronie JSP.

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

Można go również użyć w porównaniu

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

Które wolę od umieszczania dosłownego ciągu.

Elektroniczny kowal
źródło
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()}
  • Umieść import na górze , w nagłówku strony JSP
  • Jeśli chcesz pracować z metodą getStatus , użyj # 1
  • Jeśli chcesz pracować z samym elementem wyliczenia , użyj jednego z nich # 2 lub # 3
  • Możesz użyć == zamiast eq
Mehdi
źródło
-1

Generalnie uważam za złą praktykę mieszanie kodu java z plikami jsps / tag. Użycie „eq” powinno załatwić sprawę:

<c:if test="${dp.Status eq 'OLD'}">
  ...
</c:if>
Eclatante
źródło
3
Więc używanie ==zamiast tego jest złą praktyką eq? Robią dokładnie to samo, więc nie ma sposobu na „sztuczkę”.
BalusC
Oczywiście nie wypowiadałem się na temat użycia eq vs ==. Wiele odpowiedzi na to pytanie dotyczyło wstawiania kodu java do plików jsp lub tagów, co może być kulą. Preferuję utrzymywanie logiki biznesowej w kodzie java (gdzie można ją łatwo i dokładnie przetestować) oddzielnie od logiki wyświetlania na stronie JSP.
Eclatante
7
Wydaje mi się, że równie złą praktyką jest wstawianie magicznych ciągów do twojego JSP, których nie może sprawdzić kompilator, gdy chcesz refaktoryzować swoje wyliczenia. Wygląda na to, że po obu stronach nie ma dobrego rozwiązania.
Lyle,
-1

Robię to w ten sposób, gdy jest wiele punktów do wykorzystania ...

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
źródło
-2

W klasie 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
}

Więc teraz tworzony jest POJO i enum obj. Teraz EnumTest ustawisz w obiekcie sesyjnym za pomocą klasy serwletu lub kontrolera session.setAttribute ("enumTest", EnumTest);

Na stronie JSP

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

//TRUE??? THEN PROCESS SOME LOGIC
Pavan
źródło