เข้าถึงค่า 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
ทำบุญ

4
ข้อกำหนด JavaServer Pages ™เวอร์ชัน 2.0 ระบุไว้ใน JSP.2.3.5.7: "•ถ้า A หรือ B เป็น String บังคับทั้ง A และ B ถึง String ให้เปรียบเทียบแบบศัพท์"
Roland Illig

11
แต่คุณเสียประโยชน์จากการมี enum: สิ่งนี้อาจนำไปสู่ความเข้าใจผิดที่ยุ่งยากหาก enum เปลี่ยนไปในวันหนึ่ง โดยปกติแล้วถ้าฉันพบว่าตัวเองเปลี่ยน enum ฉันรู้สึกปลอดภัยมากและอาจจะจำไม่ได้ว่าการอ้างอิงสตริงถึง enum ในมุมมองนั้น ...
reallynice

1
สิ่งนี้เปรียบเทียบกับ toString of the enum หรือไม่? ดังนั้นหากคุณแทนที่ toString (เช่นคุณต้องการชื่อที่แสดงที่จำง่าย) คุณต้องแน่ใจว่าคุณได้เปลี่ยนค่าที่จับคู่ด้วย
Rupert Madden-Abbott

1
FWIW วันนี้บน Java 8 ของฉัน (IBM Java สำหรับ WebSphere ในกรณีที่มีความสำคัญ) ดูเหมือนจะไม่ได้ผล ดูเหมือนว่าจะใช้ได้ผลก็ต่อเมื่อเปรียบเทียบกับค่าสตริงซึ่งในที่นี้จะเป็นตัวพิมพ์เล็ก "เก่า"
dbreaux

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
ดูเหมือนว่าจะใช้ไม่ได้กับ enums ภายใน? เกิดจาก: org.springframework.expression.spel.SpelEvaluationException: EL1005E: (pos 0): ไม่พบประเภท 'my.package.model.EngagementRequest.EngagementStatus'
Eddie

4
ลองใช้ 'my.package.model.EngagementRequest $ EngagementStatus'
James

สิ่งที่ดีเกี่ยวกับวิธีแก้ปัญหานี้คือคุณได้รับข้อความแสดงข้อผิดพลาดหากมีข้อผิดพลาดในการแสดงออกของคุณซึ่งไม่ได้เกิดขึ้นเสมอไป<c:if>และ<c:when>(พวกเขาล้มเหลวอย่างเงียบ ๆ )
vegemite4me

41

คุณมี 3 ทางเลือกที่นี่ไม่มีข้อใดสมบูรณ์แบบ:

  1. คุณสามารถใช้ scriptlet ในtestแอตทริบิวต์:

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

    สิ่งนี้ใช้ enum แต่ยังใช้ scriptlet ซึ่งไม่ใช่ "วิธีที่ถูกต้อง" ใน JSP 2.0 แต่ที่สำคัญที่สุดนี้ไม่ทำงานเมื่อคุณต้องการที่จะเพิ่มเงื่อนไขอื่นเพื่อเดียวกันใช้when ${}และนี่หมายความว่าตัวแปรทั้งหมดที่คุณต้องการทดสอบจะต้องประกาศใน scriptlet หรือเก็บไว้ในคำขอหรือเซสชัน ( pageContextตัวแปรไม่มีอยู่ใน.tagไฟล์)

  2. คุณสามารถเปรียบเทียบกับสตริง:

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

    สิ่งนี้ดูสะอาดตา แต่คุณกำลังแนะนำสตริงที่ซ้ำกับค่า enum และคอมไพเลอร์ไม่สามารถตรวจสอบได้ ดังนั้นหากคุณลบค่านั้นออกจาก enum หรือเปลี่ยนชื่อคุณจะไม่เห็นว่าส่วนนี้ของโค้ดไม่สามารถเข้าถึงได้อีกต่อไป โดยทั่วไปคุณต้องทำการค้นหา / แทนที่รหัสทุกครั้ง

  3. คุณสามารถเพิ่มค่า enum แต่ละค่าที่คุณใช้ลงในบริบทของเพจ:

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

    จากนั้นคุณสามารถทำได้:

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

ฉันชอบตัวเลือกสุดท้าย (3) แม้ว่าจะใช้ scriptlet ด้วยก็ตาม เนื่องจากจะใช้เฉพาะเมื่อคุณตั้งค่า ในภายหลังคุณสามารถใช้ในนิพจน์ EL ที่ซับซ้อนมากขึ้นพร้อมกับเงื่อนไข EL อื่น ๆ ในขณะที่ตัวเลือก (1) คุณไม่สามารถใช้ scriptlet และนิพจน์ EL ในtestแอตทริบิวต์ของ singlewhenแท็ก


1
เกี่ยวกับตัวเลือก 2 คอมไพลเลอร์ไม่สามารถตรวจสอบได้ แต่ในรันไทม์สตริงจะถูกแปลงเป็น enum โดยใช้Enum.valueOf(Class<T> enumType, String name)ซึ่งจะทริกเกอร์ELExceptionถ้า enum ไม่มีค่าคงที่กับชื่อนั้น นิพจน์จะไม่เป็นเพียงเท็จเสมอไป
รีบูต

23

ดังนั้นเพื่อให้ปัญหาของฉันได้รับการแก้ไขอย่างสมบูรณ์ฉันต้องทำสิ่งต่อไปนี้:

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

จากนั้นฉันก็สามารถทำได้:

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

ซึ่งทำงานได้ตามที่คาดไว้


12
การใช้ scriptlets เป็นรูปแบบที่ไม่ดี
Eugene Retunsky

14

นี่คือความเป็นไปได้อีกสองประการ:

ค่าคงที่ JSP EL 3.0

ตราบใดที่คุณใช้ EL เวอร์ชัน 3.0 เป็นอย่างน้อยคุณสามารถนำเข้าค่าคงที่ลงในเพจของคุณได้ดังนี้:

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

อย่างไรก็ตาม IDE บางคนยังไม่เข้าใจสิ่งนี้ (เช่นIntelliJ ) ดังนั้นคุณจะไม่ได้รับคำเตือนใด ๆ หากคุณพิมพ์ผิดจนกว่าจะรันไทม์

นี่เป็นวิธีที่ฉันต้องการเมื่อได้รับการสนับสนุน IDE ที่เหมาะสม

วิธีการช่วยเหลือ

คุณสามารถเพิ่ม getters ลงใน enum ของคุณได้

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 ได้ นี่คือสิ่งที่ฉันทำในขณะนี้เพราะมันทำให้ตรรกะทั้งหมดรวมอยู่ใน enum ของฉัน

ระวังด้วยว่าตัวแปรที่จัดเก็บ enum เป็นโมฆะ คุณจะต้องตรวจสอบก่อนหากรหัสของคุณไม่รับประกันว่าจะไม่เป็นโมฆะ:

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

ฉันคิดว่าวิธีนี้ดีกว่าวิธีที่คุณตั้งค่าตัวกลางใน JSP เพราะคุณต้องทำเช่นนั้นในแต่ละหน้าซึ่งคุณต้องใช้ enum อย่างไรก็ตามด้วยวิธีนี้คุณจะต้องประกาศ getter เพียงครั้งเดียว


2
ส่วน "JSP EL 3.0 Constants" ต้องเป็นคำตอบที่ยอมรับได้เนื่องจากเป็นวิธีมาตรฐานในการบรรลุผลลัพธ์ที่ต้องการโดยใช้ฟังก์ชันในตัว หมายเหตุด้านข้าง InteliJ IDEA (อย่างน้อยรุ่น Ultimate 2017.2.4) รองรับการใช้งานนอกกรอบและแสดงรายการค่าคงที่ที่มีเมื่อคุณพิมพ์${MyEnum.}ใส่เครื่องหมายคาเร็ตไว้หลังจุดแล้วกดCtrl+Spaceเพื่อแสดงคำแนะนำ
izogfif

[ UPDATE ] ดูเหมือนว่า IntelliJ IDEA ได้แก้ไขปัญหาที่กล่าวถึงในคำตอบนี้แล้ว
informatik01


3

ฉันไม่มีคำตอบสำหรับคำถามของ Kornel แต่ฉันมีข้อสังเกตเกี่ยวกับตัวอย่างสคริปต์อื่น ๆ การแสดงออกส่วนใหญ่ไว้วางใจโดยปริยาย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
  • คุณสามารถใช้==แทนeq

-1

โดยทั่วไปฉันคิดว่าเป็นแนวทางปฏิบัติที่ไม่ดีในการผสมโค้ด java ลงในไฟล์ jsps / tag การใช้ 'eq' ควรทำเคล็ดลับ:

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

3
ดังนั้นจึงเป็นวิธีปฏิบัติที่ไม่ดีที่จะใช้==แทนeq? ทั้งคู่ทำเหมือนกันทุกประการดังนั้นจึงไม่มี "เคล็ดลับ"
BalusC

แน่นอนฉันไม่ได้แถลงเกี่ยวกับการใช้ eq vs == คำตอบมากมายสำหรับคำถามนี้เกี่ยวข้องกับการใส่โค้ด java ลงในไฟล์ jsp หรือ tag ซึ่งอาจเป็นไม้ค้ำยัน ฉันชอบเก็บตรรกะทางธุรกิจไว้ในโค้ด java (ซึ่งสามารถทดสอบหน่วยได้ง่ายและละเอียดถี่ถ้วน) แยกจากตรรกะการแสดงผลใน JSP
Eclatante

7
สำหรับฉันแล้วการใส่สตริงเวทมนต์ลงใน JSP ของคุณซึ่งไม่สามารถตรวจสอบได้โดยคอมไพเลอร์เมื่อคุณต้องการ refactor enums ของคุณ ดูเหมือนว่าทั้งสองฝ่ายจะไม่มีทางออกที่ดี
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 และ enum obj ถูกสร้างขึ้น ตอนนี้EnumTestคุณจะตั้งค่าในวัตถุเซสชันโดยใช้ในคลาส servlet หรือ controller session.setAttribute ("enumTest", EnumTest);

ในหน้า JSP

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

//TRUE??? THEN PROCESS SOME LOGIC
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.