Доступ до значення Enum за допомогою EL за допомогою JSTL


104

У мене Enum називається Статус визначений як такий:

public enum Status { 

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

    private final String val;

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

    public String getStatus() {
        return val;
    }

}

Я хотів би отримати значення VALIDвід тегу JSTL. Зокрема testатрибут <c:when>тегу. Напр

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

Я не впевнений, чи можливо це.

Відповіді:


112

Просте порівняння з рядковими роботами:

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

11
Для тих, хто потребує джерела: Це зазначено (наприклад) у розділі 1.17 "Специфікації мови виразів, версія 2.2", що є частиною JSR-245 .
meriton

4
Специфікація JavaServer Pages ™, Версія 2.0, в JSP.2.3.5.7 зазначає: "• Якщо A або B є String примусовим і A, і B до String, порівняйте лексично"
Roland Illig

11
Але ви втрачаєте перевагу наявності перерахунку: це може призвести до громіздких непорозумінь, якщо перерахунок зміниться одного дня. Зазвичай, якщо я виявляю, що я змінюю перерахунок, я відчуваю себе досить безпечно, і, напевно, я б не пам’ятав цього посилання на рядок до перерахунку в цьому погляді ...
realnice

1
Чи це порівняння проти тональності перерахунку? Отже, якщо ви переосмислите toString (наприклад, ви хочете дружнє ім'я відображення), тоді вам потрібно переконатися, що ви також змінили значення, з яким порівнюється.
Руперт Мадден-Абботт

1
FWIW, сьогодні на моєму Java 8 (IBM Java для WebSphere, якщо це має значення), схоже, це не працює. Здається, це працює лише в тому випадку, якщо порівнювати значення рядка з
великим

54

Якщо ви використовуєте Spring MVC, мова Spring Expression (SpEL) може бути корисною:

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

1
Здається, це не працює для внутрішніх переживань? Викликано: org.springframework.expression.spel.SpelEvaluationException: EL1005E: (поз. 0): тип не можна знайти 'my.package.model.EngagementRequest.EngagementStatus'
Едді

4
Спробуйте використовувати "my.package.model.EngagementRequest $ EngagementStatus"
Джеймс

Хороша річ у цьому рішенні - це те, що ви отримуєте повідомлення про помилку, якщо у вашому вираженні є помилка, що не завжди трапляється з <c:if>і <c:when>(вони виходять з ладу).
vegemite4me

41

Тут у вас є 3 варіанти, жоден з яких не ідеальний:

  1. Ви можете використовувати сценарій в testатрибуті:

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

    При цьому використовується enum, але він також використовує скриплет, який не є "правильним шляхом" в JSP 2.0. Але найголовніше, що це не працює, коли ви хочете додати ще одну умову до тієї ж, whenвикористовуючи ${}. А це означає, що всі змінні, які ви хочете перевірити, повинні бути задекларовані в сценарії, або збережені в запиті або сеансі ( pageContextзмінна недоступна у .tagфайлах).

  2. Ви можете порівняти з рядком:

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

    Це виглядає чисто, але ви вводите рядок, що дублює значення enum і не може бути перевірений компілятором. Тож якщо ви вилучите це значення з enum або перейменуєте його, ви не побачите, що ця частина коду вже недоступна. В основному вам потрібно робити пошук / заміну через код кожен раз.

  3. Ви можете додати кожне із використаних значень перерахувань до контексту сторінки:

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

    і тоді ви можете це зробити:

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

Я віддаю перевагу останній варіант (3), навіть якщо він також використовує сценарій. Це тому, що він використовує його лише тоді, коли ви встановлюєте значення. Пізніше ви можете використовувати його у більш складних виразах EL разом з іншими умовами EL. Перебуваючи у варіанті (1), ви не можете використовувати скриплет та вираз EL в testатрибуті одного whenтегу.


1
Щодо варіанту 2, компілятор не може його перевірити, але під час виконання рядок буде перетворений на enum, використовуючи Enum.valueOf(Class<T> enumType, String name)який запустить a, ELExceptionякщо enum не має константи з цим ім'ям. Вираз не завжди буде хибним.
Перезавантажтесь

23

Отже, щоб повністю вирішити свою проблему, мені потрібно було зробити наступне:

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

Тоді я зміг зробити:

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

яка працювала як очікувалося.


12
використання сценаріїв - це поганий стиль.
Євген Ретунський

13

Ось ще дві можливості:

Константи JSP EL 3.0

Поки ви використовуєте принаймні версію 3.0 версії EL, ви можете імпортувати константи на свою сторінку наступним чином:

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

Однак деякі IDE цього ще не розуміють (наприклад, IntelliJ ), тому ви не отримаєте жодних попереджень, якщо зробите помилку, до моменту виконання.

Це був би мій кращий метод, як тільки він отримає належну підтримку IDE.

Методи допомоги

Ви можете просто додати гетерів до перерахунку.

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

Потім у своєму JSP:

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

Це підтримується у всіх IDE, а також буде працювати, якщо ви ще не можете використовувати EL 3.0. Це те, що я роблю на даний момент, тому що воно зберігає всю логіку, загорнуту в мою суть.

Також будьте обережні, якщо можливо, що змінна, що зберігає перерахунок, є нульовою. Вам слід спочатку перевірити, чи ваш код не гарантує, що він недійсний:

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

Я думаю, що цей метод перевершує ті, де ви встановлюєте посередницьке значення в JSP, оскільки це потрібно робити на кожній сторінці, де вам потрібно використовувати enum. Однак з цим рішенням вам потрібно оголосити геттера лише один раз.


2
Частина "Константи JSP EL 3.0" повинна бути прийнятою відповіддю, оскільки це стандартний спосіб досягти необхідного результату за допомогою вбудованої функціональності. Зі сторони, InteliJ IDEA (принаймні, Ultimate версія 2017.2.4) підтримує його поза полем і показує список доступних констант під час введення ${MyEnum.}, кладеть карету відразу після крапки і натискаємо, Ctrl+Spaceщоб показати пропозиції.
izogfif

[ UPDATE ] Схоже, IntelliJ IDEA вже вирішив проблему, згадану в цій відповіді.
informatik01

10

Для цього я роблю наступне:

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

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

Це виглядає некрасиво, але працює!


3

У мене немає відповіді на запитання Корнеля, але у мене є зауваження щодо інших прикладів сценарію. Більшість виразів довірно покладається на toString(), але Enum.valueOf()очікує значення, яке походить від / відповідає Enum.name()властивості. Тому слід використовувати, наприклад:

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

2

Додайте метод до enum, як:

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

Наприклад

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

Тоді ви можете використовувати:

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

1

Під час використання фрейма MVC я помістив у свій контролер наступне.

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

Це дозволяє мені використовувати таке на своїй сторінці JSP.

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

Він також може бути використаний у вашому порівнянні

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

Якому я віддаю перевагу над введенням рядкового літералу.


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()}
  • Поставте імпорт вгорі , у заголовку сторінки JSP
  • Якщо ви хочете працювати з методом getStatus , використовуйте №1
  • Якщо ви хочете працювати з самим елементом enum , використовуйте або №2, або №3
  • Ви можете використовувати == замість еквівалента

-1

Я взагалі вважаю поганою практикою змішувати код Java у файли jsps / tag. Використовуючи 'eq', слід зробити таке:

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

3
Тож це погана практика використовувати ==замість eq? Вони обидва роблять точно так само, тому немає жодного засобу "хитрості".
BalusC

Звичайно, я не робив заяви про використання eq vs ==. Багато відповідей на це запитання стосувалися вставки коду Java у файли jsp або тегів, які можуть бути милицями. Я віддаю перевагу, щоб бізнес-логіка в коді Java (там, де її можна легко і ретельно перевірити), була окремою від логіки відображення в JSP.
Еклатанте

7
Мені здається не менш поганою практикою вставляти в свій JSP магічні рядки, які компілятор не може перевірити, коли ти хочеш змінити свої перерахунки. Здається, немає хорошого рішення для цього з обох сторін.
Лайл

-1

Я роблю це так, коли є багато точок, які потрібно використати ...

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

У класі 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
}

Тож тепер створено POJO та enum obj. Тепер EnumTest ви встановите в об'єкт сеансу, використовуючи в сервлеті або контролері клас session.setAttribute ("enumTest", EnumTest);

На сторінці JSP

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

//TRUE??? THEN PROCESS SOME LOGIC
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.