使用EL与JSTL访问枚举值

我有一个名为状态的枚举定义如下:

public enum Status { VALID("valid"), OLD("old"); private final String val; Status(String val) { this.val = val; } public String getStatus() { return val; } } 

我想从JSTL标签访问VALID的值。 具体来说就是<c:when>标签的test属性。 例如

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

我不确定这是否可能。

一个简单的对比string的作品:

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

如果使用Spring MVC,Springexpression式语言(SpEL)可能会有所帮助:

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

你在这里有三个select,没有一个是完美的:

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

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

    这使用枚举,但它也使用了一个scriptlet,这不是JSP 2.0中的“正确方法”。 但最重要的是,当你想when使用${} when添加另外一个条件的时候,这是行不通的。 这意味着你想testing的所有variables都必须在scriptlet中声明,或者保存在请求中,或者session( pageContextvariables在.tag文件中不可用)。

  2. 你可以比较string:

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

    这看起来很干净,但是你引入了一个重复枚举值的string,不能被编译器validation。 因此,如果您从枚举中删除该值或将其重命名,则不会看到这部分代码无法再访问。 你基本上每次都必须通过代码进行search/replace。

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

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

    然后你可以这样做:

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

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

所以为了让我的问题完全解决,我需要做到以下几点:

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

然后我能够做到:

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

按预期工作。

为此,我做了以下几点:

 <c:set var="abc"> <%=Status.OLD.getStatus()%> </c:set> <c:if test="${someVariable == abc}"> .... </c:if> 

这看起来丑陋,但工作!

我对科尔内尔的问题没有一个答案,但是我对其他脚本例子有所评论。 大部分expression式都隐式地信任toString() ,但是Enum.valueOf()需要一个来自/匹配Enum.name()属性的值。 所以应该使用例如:

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

这里有两个更多的可能性:

JSP EL 3.0常量

只要你至less使用版本3.0的EL,那么你可以将常量导入到你的页面中,如下所示:

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

但是,有些IDE还不能理解这个(例如IntelliJ ),所以如果你input错误,你将不会得到任何警告,直到运行时。

一旦获得适当的IDE支持,这将是我的首选方法。

帮手方法

你可以添加getters到你的枚举。

 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的话,它也可以工作。 这是我现在所做的,因为它保留了所有的逻辑包裹到我的枚举。

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

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

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

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

当使用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}"> 

我更喜欢把一个string文字。

我通常认为将java代码混合到jsps / tag文件是一个糟糕的做法。 使用'eq'应该可以做到这一点:

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

在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被创build。 现在, EnumTest将在会话对象中使用servlet或控制器类session.setAttribute(“enumTest”,EnumTest);

在JSP页面中

 <c:if test="${enumTest.statusobj == 'ACTIVE'}"> //TRUE??? THEN PROCESS SOME LOGIC