Truy cập giá trị Enum bằng EL với JSTL


104

Tôi có một Enum được gọi là Trạng thái được định nghĩa như vậy:

public enum Status { 

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

    private final String val;

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

    public String getStatus() {
        return val;
    }

}

Tôi muốn truy cập giá trị của VALIDtừ thẻ JSTL. Cụ thể là testthuộc tính của <c:when>thẻ. Ví dụ

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

Tôi không chắc liệu điều này có khả thi hay không.

Câu trả lời:


112

Một phép so sánh đơn giản với chuỗi hoạt động:

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

11
Đối với những người yêu cầu nguồn: Điều này được chỉ định (ví dụ) trong phần 1.17 của "Đặc tả ngôn ngữ biểu thức, phiên bản 2.2", là một phần của JSR-245 .
Meriton

4
Các JavaServer Pages ™ Thông số kỹ thuật, phiên bản 2.0 cho biết trong JSP.2.3.5.7: "• Nếu A hoặc B là String ép buộc cả A và B để String, so sánh lexically"
Roland Illig

11
Nhưng bạn đã đánh mất lợi thế của việc có một enum: điều này có thể dẫn đến những hiểu lầm phức tạp nếu một ngày nào đó enum bị thay đổi. Thông thường, nếu tôi thấy mình thay đổi một enum, tôi cảm thấy khá an toàn, và có lẽ tôi sẽ không nhớ rằng chuỗi-to-enum tham chiếu theo quan điểm đó ...
reallynice

1
Điều này có so sánh với toString của enum không? Vì vậy, nếu bạn ghi đè toString (ví dụ: bạn muốn một tên hiển thị thân thiện), thì bạn cần đảm bảo rằng bạn cũng thay đổi giá trị được so khớp với.
Rupert Madden-Abbott

1
FWIW, hôm nay trên Java 8 của tôi (IBM Java cho WebSphere, trong trường hợp có vấn đề), điều này dường như không hoạt động. Dường như với việc chỉ khi so sánh với các chuỗi giá trị, mà ở đây sẽ là trường hợp thấp hơn "cũ"
dbreaux

54

Nếu sử dụng Spring MVC, thì Ngôn ngữ biểu thức mùa xuân (SpEL) có thể hữu ích:

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

1
Có vẻ như điều này không hiệu quả đối với các enums trong? Gây ra bởi: org.springframework.expression.spel.SpelEvaluationException: EL1005E: (pos 0): Loại không thể tìm thấy 'my.package.model.EngagementRequest.EngagementStatus'
Eddie

4
Hãy thử sử dụng 'my.package.model.EngagementRequest $ EngagementStatus'
James

Một điều tốt về giải pháp này là bạn sẽ nhận được thông báo lỗi nếu có sai sót trong biểu thức của bạn, điều này không phải lúc nào cũng xảy ra với <c:if><c:when>(chúng không thành công một cách lặng lẽ).
vegemite4me

41

Bạn có 3 lựa chọn ở đây, không cái nào là hoàn hảo:

  1. Bạn có thể sử dụng tập lệnh trong testthuộc tính:

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

    Điều này sử dụng enum, nhưng nó cũng sử dụng scriptlet, đây không phải là "cách đúng đắn" trong JSP 2.0. Nhưng quan trọng nhất, điều này không hoạt động khi bạn muốn thêm một điều kiện khác vào cùng một whencách sử dụng ${}. Và điều này có nghĩa là tất cả các biến bạn muốn kiểm tra phải được khai báo trong một script, hoặc được lưu giữ trong yêu cầu hoặc phiên ( pageContextbiến không có sẵn trong .tagtệp).

  2. Bạn có thể so sánh với chuỗi:

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

    Điều này trông có vẻ rõ ràng, nhưng bạn đang giới thiệu một chuỗi sao chép giá trị enum và trình biên dịch không thể xác thực. Vì vậy, nếu bạn xóa giá trị đó khỏi enum hoặc đổi tên nó, bạn sẽ không thấy rằng phần mã này không thể truy cập được nữa. Về cơ bản, bạn phải thực hiện tìm kiếm / thay thế thông qua mã mỗi lần.

  3. Bạn có thể thêm từng giá trị enum mà bạn sử dụng vào ngữ cảnh trang:

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

    và sau đó bạn có thể làm điều này:

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

Tôi thích tùy chọn cuối cùng (3) hơn, mặc dù nó cũng sử dụng script. Điều này là do nó chỉ sử dụng nó khi bạn đặt giá trị. Sau này, bạn có thể sử dụng nó trong các biểu thức EL phức tạp hơn, cùng với các điều kiện EL khác. Trong tùy chọn (1), bạn không thể sử dụng tập lệnh và biểu thức EL trong testthuộc tính của một whenthẻ.


1
Đối với tùy chọn 2, trình biên dịch không thể xác minh nó, nhưng trong thời gian chạy, chuỗi sẽ được chuyển đổi thành một enum bằng cách sử dụng Enum.valueOf(Class<T> enumType, String name)nó sẽ kích hoạt ELExceptionnếu enum không có hằng số với tên đó. Biểu thức sẽ không phải lúc nào cũng sai.
Khởi động lại

23

Vì vậy, để vấn đề của tôi được giải quyết hoàn toàn, tôi cần thực hiện những việc sau:

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

Sau đó, tôi đã có thể làm:

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

đã hoạt động như mong đợi.


12
sử dụng scriptlets là một phong cách tồi.
Eugene Retunsky

13

Đây là hai khả năng khác:

Các hằng số JSP EL 3.0

Miễn là bạn đang sử dụng ít nhất phiên bản 3.0 của EL, thì bạn có thể nhập các hằng số vào trang của mình như sau:

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

Tuy nhiên, một số IDE chưa hiểu điều này (ví dụ: IntelliJ ), vì vậy bạn sẽ không nhận được bất kỳ cảnh báo nào nếu bạn mắc lỗi chính tả, cho đến thời gian chạy.

Đây sẽ là phương pháp ưa thích của tôi khi nó được hỗ trợ IDE thích hợp.

Phương pháp người trợ giúp

Bạn chỉ có thể thêm getters vào enum của mình.

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

Sau đó, trong JSP của bạn:

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

Điều này được hỗ trợ trong tất cả các IDE và cũng sẽ hoạt động nếu bạn chưa thể sử dụng EL 3.0. Đây là những gì tôi làm vào lúc này vì nó giữ tất cả logic được gói gọn trong enum của tôi.

Cũng hãy cẩn thận nếu biến lưu trữ enum có thể là null. Bạn sẽ cần kiểm tra điều đó trước nếu mã của bạn không đảm bảo rằng nó không rỗng:

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

Tôi nghĩ rằng phương pháp này tốt hơn so với những phương pháp mà bạn đặt giá trị trung gian trong JSP vì bạn phải làm điều đó trên mỗi trang mà bạn cần sử dụng enum. Tuy nhiên, với giải pháp này bạn chỉ cần khai báo getter một lần.


2
Phần "Hằng số JSP EL 3.0" phải là câu trả lời được chấp nhận vì đó là cách tiêu chuẩn để đạt được kết quả cần thiết bằng cách sử dụng chức năng tích hợp sẵn. Một lưu ý nhỏ là InteliJ IDEA (ít nhất là phiên bản Ultimate 2017.2.4) không hỗ trợ nó và hiển thị danh sách các hằng số có sẵn khi bạn nhập ${MyEnum.}, hãy đặt dấu mũ ngay sau dấu chấm và nhấn Ctrl+Spaceđể hiển thị đề xuất.
izogfif

[ UPDATE ] Có vẻ như IntelliJ IDEA đã khắc phục sự cố được đề cập trong câu trả lời này.
Informatik01

10

Vì mục đích này, tôi làm như sau:

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

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

Nó trông xấu xí, nhưng hoạt động!


3

Tôi không có câu trả lời cho câu hỏi của Kornel, nhưng tôi có một nhận xét về các ví dụ kịch bản khác. Hầu hết biểu thức tin cậy ngầm vào toString(), nhưng Enum.valueOf()giá trị mong đợi một giá trị đến từ / khớp với thuộc Enum.name()tính. Vì vậy, người ta nên sử dụng ví dụ:

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

2

Thêm một phương thức vào enum như:

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

Ví dụ

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

Sau đó, bạn có thể sử dụng:

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

1

Khi sử dụng khung công tác MVC, tôi đặt phần sau vào bộ điều khiển của mình.

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

Điều này cho phép tôi sử dụng phần sau trong Trang JSP của mình.

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

Nó cũng có thể được sử dụng để so sánh của bạn

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

Điều mà tôi thích hơn là đặt một chuỗi theo nghĩa đen.


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()}
  • Đặt nhập ở trên cùng , trong tiêu đề trang JSP
  • Nếu bạn muốn làm việc với phương thức getStatus , hãy sử dụng # 1
  • Nếu bạn muốn làm việc với chính phần tử enum , hãy sử dụng # 2 hoặc # 3
  • Bạn có thể sử dụng == thay vì eq

-1

Tôi thường coi việc trộn mã java vào các tệp jsps / tag. Sử dụng 'eq' sẽ thực hiện thủ thuật:

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

3
Vì vậy, nó là một thực hành xấu để sử dụng ==thay thế eq? Cả hai đều hoàn toàn giống nhau, vì vậy không có nghĩa là "lừa".
BalusC

Tất nhiên, tôi đã không đưa ra tuyên bố về việc sử dụng eq vs ==. Nhiều câu trả lời cho câu hỏi này liên quan đến việc chèn mã java vào các tệp jsp hoặc thẻ có thể là một nguyên nhân. Tôi ủng hộ việc giữ logic nghiệp vụ trong mã java (nơi nó có thể được kiểm tra đơn vị một cách dễ dàng và kỹ lưỡng) tách biệt với logic hiển thị trong JSP.
Eclatante

7
Đối với tôi, việc chèn các chuỗi ma thuật vào JSP của bạn mà trình biên dịch không thể kiểm tra được khi bạn muốn cấu trúc lại các enums có vẻ là một việc làm tồi tệ không kém. Có vẻ như không có giải pháp tốt cho điều này cho cả hai bên.
Lyle

-1

Tôi làm theo cách này khi có nhiều điểm sử dụng ...

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

Trong lớp 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
}

Vì vậy, bây giờ POJO và enum obj được tạo. Bây giờ EnumTest bạn sẽ đặt trong đối tượng phiên sử dụng trong lớp servlet hoặc bộ điều khiển session.setAttribute ("enumTest", EnumTest);

Trong trang JSP

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

//TRUE??? THEN PROCESS SOME LOGIC
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.