使用EL和JSTL访问Enum值


104

我有一个名为Status的枚举,其定义如下:

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

我不确定是否可行。

Answers:


112

与字符串的简单比较:

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

11
对于那些需要源代码的用户:(例如)在JSR-245的“表达式语言规范,版本2.2”的1.17节中对此进行了指定。
meriton

4
JavaServer Pages™规范版本2.0在JSP.2.3.5.7中说:“•如果A或B为字符串,则将A和B都强制转换为String,请按词法进行比较”
Roland Illig

11
但是,您失去了拥有枚举的优势:如果枚举一天被更改,这可能导致麻烦的误解。通常,如果我发现自己正在更改一个枚举,我会觉得很安全,并且也许我不会记住该视图中的字符串到枚举的引用……
确实不错,2014年

1
这是否与枚举的toString相比较?因此,如果您覆盖toString(例如,您想要一个友好的显示名称),则需要确保您还更改了要匹配的值。
鲁珀特·马登·阿博特

1
FWIW,今天在我的Java 8(如果需要的话,请使用IBM Java for WebSphere)上,这似乎不起作用。它似乎仅在与字符串值进行比较时才起作用,在这里字符串将是小写的“ old”
dbreaux '18

54

如果使用Spring MVC,Spring Expression Language(SpEL)可能会有所帮助:

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

1
似乎这对于内部枚举不起作用?型不能被发现'my.package.model.EngagementRequest.EngagementStatus':org.springframework.expression.spel.SpelEvaluationException:EL1005E:(位置0)而引起
埃迪

4
尝试使用“ my.package.model.EngagementRequest $ EngagementStatus”
James

关于此解决方案的一个好处是,如果表达式中有错误,您会收到一条错误消息,这种错误并不总是与<c:if>和发生的<c:when>(它们会悄然失败)。
vegemite4me 2015年

41

您在这里有3个选择,没有一个是完美的:

  1. 您可以在test属性中使用脚本:

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

    这使用了枚举,但也使用了scriptlet,这不是JSP 2.0中的“正确方法”。但最重要的是,当您想when使用来向同一条件添加其他条件时,此方法不起作用${}。这意味着您要测试的所有变量都必须在scriptlet中声明,或者保留在请求或会话中(pageContext变量在.tag文件中不可用)。

  2. 您可以将其与字符串进行比较:

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

    这看起来很干净,但是您要引入一个字符串,该字符串重复枚举值,并且编译器无法对其进行验证。因此,如果您从枚举中删除该值或对其进行重命名,您将不会再看到此部分代码。基本上,您每次都必须在代码中进行搜索/替换。

  3. 您可以将使用的每个枚举值添加到页面上下文中:

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

    然后您可以执行以下操作:

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

我更喜欢最后一个选项(3),尽管它也使用了scriptlet。这是因为它仅在设置值时使用。稍后,您可以将其与其他EL条件一起用于更复杂的EL表达式中。在选项(1)中,不能在test单个when标签的属性中使用scriptlet和EL表达式。


1
关于选项2,编译器无法对其进行验证,但是在运行时,该字符串将转换为枚举Enum.valueOf(Class<T> enumType, String name)ELException如果枚举没有该名称的常量,则使用该枚举将触发。该表达式不仅会始终为假。
重新启动2014年

23

因此,要使我的问题得到完全解决,我需要执行以下操作:

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

然后,我能够做到:

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

它按预期工作。


12
使用scriptlet是不好的风格。
Eugene Retunsky 2013年

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,也可以使用。这是我目前要做的,因为它将所有逻辑包裹在枚举中。

如果存储枚举的变量可能为空,也要小心。如果您的代码不能保证它不为null,则需要先检查该代码:

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

我认为此方法优于在JSP中设置中间值的方法,因为您必须在需要使用枚举的每个页面上执行此操作。但是,使用此解决方案,您只需要声明一次getter。


2
必须接受“ JSP EL 3.0常量”部分,因为这是使用内置功能获得所需结果的标准方法。附带一提,InteliJ IDEA(至少是Ultimate版本2017.2.4)确实支持该功能,并在您键入时显示可用常量列表${MyEnum.},将插入号放在点后并按Ctrl+Space以显示建议。
izogfif

[ 更新 ]似乎IntelliJ IDEA已经解决了此答案中提到的问题。
informatik01

10

为此,我执行以下操作:

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

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

看起来很丑,但是行得通!


3

我没有关于Kornel问题的答案,但是我对其他脚本示例有意见。大多数表达式都隐式信任toString(),但是Enum.valueOf()期望值来自/匹配Enum.name()属性。因此,应使用例如:

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

2

向枚举中添加一个方法,例如:

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
  • 如果要使用枚举元素本身,请使用#2或#3
  • 您可以使用==代替eq

-1

我通常认为将Java代码混入jsps / tag文件是一种不好的做法。使用'eq'应该可以解决问题:

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

3
因此,使用==而不是不好的做法eq?他们做的完全一样,所以没有“把戏”的手段。
BalusC,2009年

当然,我没有就eq vs ==的使用发表任何声明。这个问题的许多答案都涉及将Java代码插入jsp或标记文件中,这可能是一个拐杖。我倾向于将业务逻辑与JSP中的显示逻辑分开,以Java代码(可以轻松,彻底地对其进行单元测试)进行保存。
Eclatante

7
对我来说,将魔术字符串插入JSP似乎同样是一种不好的做法,当您要重构枚举时,编译器将无法对其进行检查。似乎双方都没有很好的解决方案。
Lyle

-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和枚举obj。现在EnumTest您将使用servlet或控制器类session.setAttribute(“enumTest”,EnumTest)在会话对象设定;

在JSP页面中

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

//TRUE??? THEN PROCESS SOME LOGIC
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.