จะอ้างอิงค่าคงที่ใน EL ได้อย่างไร?


106

คุณอ้างอิงค่าคงที่ด้วย EL บนหน้า JSP ได้อย่างไร

ฉันมีอินเตอร์เฟซที่มีอย่างต่อเนื่องที่มีชื่อว่าAddresses URLฉันรู้ว่าฉันสามารถอ้างอิงด้วย scriplet ได้โดยไปที่: <%=Addresses.URL%>แต่ฉันจะใช้ EL ได้อย่างไร

คำตอบ:


156

EL 3.0 หรือใหม่กว่า

หากคุณใช้ Java EE 7 / EL 3.0 อยู่แล้วระบบ@page importจะนำเข้าค่าคงที่ของคลาสในขอบเขต EL ด้วย

<%@ page import="com.example.YourConstants" %>

สิ่งนี้จะนำเข้าภายใต้ฝาครอบImportHandler#importClass()และพร้อมใช้งานในรูปแบบ${YourConstants.FOO}.

หมายเหตุว่าทุกjava.lang.*ชั้นเรียนที่มีอยู่แล้วที่นำเข้าโดยปริยายและสามารถใช้ได้เช่นดังนั้นและ${Boolean.TRUE} ${Integer.MAX_VALUE}สิ่งนี้ต้องการเซิร์ฟเวอร์คอนเทนเนอร์ Java EE 7 ที่ใหม่กว่าเท่านั้นเนื่องจากเวอร์ชันแรก ๆ มีข้อบกพร่องในสิ่งนี้ เช่น GlassFish 4.0 และ Tomcat 8.0.0-1x ล้มเหลว แต่ GlassFish 4.1+ และ Tomcat 8.0.2x + ใช้งานได้ และคุณต้องตรวจสอบให้แน่ใจว่าweb.xmlประกาศของคุณเป็นไปตามเวอร์ชัน servlet ล่าสุดที่เซิร์ฟเวอร์รองรับ ดังนั้นด้วยคุณสมบัติweb.xmlที่ประกาศว่าเป็นไปตาม Servlet 2.5 หรือเก่ากว่าจึงไม่มีคุณสมบัติของ Servlet 3.0+ ที่จะทำงานได้

โปรดทราบว่าสิ่งอำนวยความสะดวกนี้มีให้บริการเฉพาะใน JSP และไม่มีใน Facelets ในกรณีของ JSF + Facelets ทางออกที่ดีที่สุดของคุณคือการใช้OmniFaces<o:importConstants>ดังต่อไปนี้:

<o:importConstants type="com.example.YourConstants" />

หรือเพิ่มตัวฟังบริบท EL ซึ่งเรียกImportHandler#importClass()ตามด้านล่าง:

@ManagedBean(eager=true)
@ApplicationScoped
public class Config {

    @PostConstruct
    public void init() {
        FacesContext.getCurrentInstance().getApplication().addELContextListener(new ELContextListener() {
            @Override
            public void contextCreated(ELContextEvent event) {
                event.getELContext().getImportHandler().importClass("com.example.YourConstants");
            }
        });
    }

}

EL 2.2 หรือเก่ากว่า

สิ่งนี้ไม่สามารถทำได้ใน EL 2.2 และเก่ากว่า มีหลายทางเลือก:

  1. ใส่ไว้ในMap<String, Object>ขอบเขตแอปพลิเคชัน ใน El ค่าแผนที่จะสามารถเข้าถึงได้ด้วยวิธีปกติโดยจาวาบีนหรือ${map.key}${map['key.with.dots']}

  2. การใช้งาน<un:useConstants>ของUnstandard taglib (Maven2 repo ที่นี่ ):

    <%@ taglib uri="http://jakarta.apache.org/taglibs/unstandard-1.0" prefix="un" %>
    <un:useConstants className="com.example.YourConstants" var="constants" />

    ${constants.FOO}วิธีที่พวกเขาจะสามารถเข้าถึงได้ตามปกติทางจาวาบีนโดย

  3. ใช้ JavaRanch ของCCC <ccc:constantsMap>เป็นที่ไหนสักแห่ง desribed ที่ด้านล่างของบทความนี้

    <%@ taglib uri="http://bibeault.org/tld/ccc" prefix="ccc" %>
    <ccc:constantsMap className="com.example.YourConstants" var="constants" />

    ด้วยวิธีนี้พวกเขาสามารถเข้าถึงได้ตามปกติของ Javabean ${constants.FOO}เช่นกัน

  4. หากคุณกำลังใช้ JSF2 แล้วคุณสามารถใช้<o:importConstants>ของOmniFaces

    <html ... xmlns:o="http://omnifaces.org/ui">
    <o:importConstants type="com.example.YourConstants" />

    ด้วยวิธีนี้พวกเขาสามารถเข้าถึงได้ตามปกติของ Javabean #{YourConstants.FOO}เช่นกัน

  5. สร้างคลาส wrapper ซึ่งส่งคืนพวกเขาผ่านเมธอด getter สไตล์ Javabean

  6. สร้างตัวแก้ไข EL แบบกำหนดเองซึ่งก่อนอื่นจะสแกนการมีอยู่ของค่าคงที่และหากไม่มีอยู่จากนั้นมอบหมายให้ตัวแก้ไขเริ่มต้นมิฉะนั้นจะส่งกลับค่าคงที่แทน


4
ฉันพบคำถามนี้เนื่องจากฉันมีปัญหาเดียวกันเมื่อพยายามใช้ฟิลด์รายการแบบคงที่กับแท็ก form: options ฉันสามารถทำให้มันใช้งานได้โดยการเพิ่ม getter แบบไม่คงที่ที่ส่งคืนรายการแบบคงที่ มันเป็นเรื่องเล็กน้อย แต่เดี๋ยวก่อนนั่นคือการพัฒนา JSP สำหรับคุณ!
spaaarky21

1
คุณมีตัวอย่างวิธีกำหนดค่านี้สำหรับ JSF หรือไม่หากถั่วได้รับการจัดการโดยสปริงหรือไม่? ขอบคุณล่วงหน้า
Lodger

2
@Lodger: ฉันไม่ทำ Spring
BalusC

2
unstandard-taglibโครงการจาการ์ตายังมีชีวิตอยู่หรือไม่? มีทางเลือกอื่นไหม
davioooh

1
มีวิธีใช้เทคนิคนี้สำหรับ enums หรือไม่?
Niklas Peter

11

สิ่งต่อไปนี้ใช้ไม่ได้กับ EL โดยทั่วไป แต่ใช้เฉพาะ SpEL (Spring EL) เท่านั้น (ทดสอบด้วย 3.2.2 ปล่อย Tomcat 7) ฉันคิดว่ามันคุ้มค่าที่จะกล่าวถึงที่นี่ในกรณีที่มีคนค้นหา JSP และ EL (แต่ใช้ JSP กับ Spring)

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<spring:eval var="constant" expression="T(com.example.Constants).CONSTANT"/>

9

คุณมักจะวางค่าคงที่ประเภทนี้ในConfigurationออบเจ็กต์ (ซึ่งมี getters และ setters) ในบริบท servlet และเข้าถึงด้วย${applicationScope.config.url}


มือใหม่เมื่อพูดถึง jsp - คุณช่วยอธิบายให้ละเอียดกว่านี้ได้ไหม
tau-neutrino

1
@ tau-neutrino: มันง่ายจริงๆ สร้างคลาสurlที่มีคุณสมบัติเป็น String ตั้งชื่อConfigurationสร้างอินสแตนซ์และตั้งค่าเป็นurlอะไรก็ได้ที่คุณต้องการ หลังจากนั้นตั้งค่าConfigurationวัตถุนั้นในServletContext. ทำสิ่งที่ชอบ, servletContext.setAttribute("config", config). แล้วคุณไป
Adeel Ansari

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

7

คุณทำไม่ได้ เป็นไปตามอนุสัญญา Java Bean ดังนั้นคุณต้องมีความเข้าใจสำหรับมัน


5

คุณสมบัติคงที่ไม่สามารถเข้าถึงได้ใน EL วิธีแก้ปัญหาที่ฉันใช้คือการสร้างตัวแปรไม่คงที่ซึ่งกำหนดค่าคงที่

public final static String MANAGER_ROLE = 'manager';
public String manager_role = MANAGER_ROLE;

ฉันใช้ลอมบ็อกเพื่อสร้างตัวรับและตัวตั้งค่าดังนั้นมันก็ค่อนข้างดี EL ของคุณมีลักษณะดังนี้:

${bean.manager_role}

รหัสเต็มที่http://www.ninthavenue.com.au/java-static-constants-in-jsp-and-jsf-el


5

ฉันดำเนินการเช่น:

public interface Constants{
    Integer PAGE_SIZE = 20;
}

-

public class JspConstants extends HashMap<String, String> {

        public JspConstants() {
            Class c = Constants.class;
            Field[] fields = c.getDeclaredFields();
            for(Field field : fields) {
                int modifier = field.getModifiers();
                if(Modifier.isPublic(modifier) && Modifier.isStatic(modifier) && Modifier.isFinal(modifier)) {
                    try {
                        Object o = field.get(null);
                        put(field.getName(), o != null ? o.toString() : null);
                    } catch(IllegalAccessException ignored) {
                    }
                }
            }
        }

        @Override
        public String get(Object key) {
            String result = super.get(key);
            if(StringUtils.isEmpty(result)) {
                throw new IllegalArgumentException("Check key! The key is wrong, no such constant!");
            }
            return result;
        }
    }

ขั้นตอนต่อไปใส่อินสแตนซ์ของคลาสนี้ลงใน servlerContext

public class ApplicationInitializer implements ServletContextListener {


    @Override
    public void contextInitialized(ServletContextEvent sce) {
        sce.getServletContext().setAttribute("Constants", new JspConstants());
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
    }
}

เพิ่ม Listener ใน web.xml

<listener>
    <listener-class>com.example.ApplicationInitializer</listener-class>
</listener>

เข้าถึงใน jsp

${Constants.PAGE_SIZE}

4

ฉันกำลังกำหนดค่าคงที่ใน jsp ของฉันตอนเริ่มต้น:

<%final String URI = "http://www.example.com/";%>

ฉันรวมแท็กลิบหลักใน JSP ของฉัน:

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

จากนั้นฉันทำให้ค่าคงที่พร้อมใช้งานสำหรับ EL โดยใช้คำสั่งต่อไปนี้:

<c:set var="URI" value="<%=URI%>"></c:set>

ตอนนี้ฉันสามารถใช้มันได้ในภายหลัง นี่คือตัวอย่างโดยที่ค่าจะถูกเขียนเป็นความคิดเห็น HTML เพื่อวัตถุประสงค์ในการดีบัก:

<!-- ${URI} -->

ด้วยคลาสคงที่ของคุณคุณสามารถนำเข้าคลาสของคุณและกำหนดค่าคงที่ให้กับตัวแปรโลคัลได้ ฉันรู้ว่าคำตอบของฉันคือการแฮ็กอย่างรวดเร็ว แต่คำถามก็เกิดขึ้นเมื่อมีคนต้องการกำหนดค่าคงที่โดยตรงใน JSP


1
ฮ่า ๆ ทำไมไม่ใช้ Scriptlets โดยตรงถ้านั่นเป็นวิธีที่คุณเริ่มต้นตัวแปร EL?
นาวิน

สามบรรทัดด้านบนเป็นระเบียบจากนั้นทำความสะอาด EL ตลอดส่วนที่เหลือของ JSP ^^
koppor

1
@koppoor ฉันเดาอย่างนั้น ฉันจะใช้<%=URI%>: P
Navin

1
ฉันมีสถานที่ที่ทางตรง<%=URI%>ไม่ได้ผล แต่เทคนิคนี้ทำได้
englebart

3

ใช่คุณสามารถ. คุณต้องมีแท็กที่กำหนดเอง (หากหาไม่ได้จากที่อื่น) ฉันได้ทำสิ่งนี้แล้ว:

package something;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Map;
import java.util.TreeMap;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;

import org.apache.taglibs.standard.tag.el.core.ExpressionUtil;

/**
 * Get all class constants (statics) and place into Map so they can be accessed
 * from EL.
 * @author Tim.sabin
 */
public class ConstMapTag extends TagSupport {
    public static final long serialVersionUID = 0x2ed23c0f306L;

    private String path = "";
    private String var = "";

    public void setPath (String path) throws JspException {
        this.path = (String)ExpressionUtil.evalNotNull ("constMap", "path",
          path, String.class, this, pageContext);
    }

    public void setVar (String var) throws JspException {
        this.var = (String)ExpressionUtil.evalNotNull ("constMap", "var",
          var, String.class, this, pageContext);
    }

    public int doStartTag () throws JspException {
        // Use Reflection to look up the desired field.
        try {
            Class<?> clazz = null;
            try {
                clazz = Class.forName (path);
            } catch (ClassNotFoundException ex) {
                throw new JspException ("Class " + path + " not found.");
            }
            Field [] flds = clazz.getDeclaredFields ();
            // Go through all the fields, and put static ones in a Map.
            Map<String, Object> constMap = new TreeMap<String, Object> ();
            for (int i = 0; i < flds.length; i++) {
                // Check to see if this is public static final. If not, it's not a constant.
                int mods = flds [i].getModifiers ();
                if (!Modifier.isFinal (mods) || !Modifier.isStatic (mods) ||
                  !Modifier.isPublic (mods)) {
                    continue;
                }
                Object val = null;
                try {
                    val = flds [i].get (null);    // null for static fields.
                } catch (Exception ex) {
                    System.out.println ("Problem getting value of " + flds [i].getName ());
                    continue;
                }
                // flds [i].get () automatically wraps primitives.
                // Place the constant into the Map.
                constMap.put (flds [i].getName (), val);
            }
            // Export the Map as a Page variable.
            pageContext.setAttribute (var, constMap);
        } catch (Exception ex) {
            if (!(ex instanceof JspException)) {
                throw new JspException ("Could not process constants from class " + path);
            } else {
                throw (JspException)ex;
            }
        }
        return SKIP_BODY;
    }
}

และแท็กเรียกว่า:

<yourLib:constMap path="path.to.your.constantClass" var="consts" />

ตัวแปรสุดท้ายแบบคงที่สาธารณะทั้งหมดจะถูกใส่ลงในแผนที่ที่จัดทำดัชนีด้วยชื่อ Java ดังนั้นถ้า

public static final int MY_FIFTEEN = 15;

จากนั้นแท็กจะรวมสิ่งนี้เป็นจำนวนเต็มและคุณสามารถอ้างอิงได้ใน JSP:

<c:if test="${consts['MY_FIFTEEN'] eq 15}">

และคุณไม่จำเป็นต้องเขียน getters!


3

คุณสามารถ. ลองทำตามวิธี

 #{T(com.example.Addresses).URL}

ทดสอบบน TomCat 7 และ java6


3
ดูเหมือน SpEL ไม่ใช่ EL ฉันเข้าใจผิดหรือเปล่า? นอกจากนี้มันจะใช้งานได้กับ Tomcat5.5 รุ่นเก่าหรือไม่?
Pytry

2

แม้จะรู้ว่ามันช้าไปหน่อยและแม้จะรู้ว่านี่เป็นการแฮ็กเล็กน้อยฉันก็ใช้วิธีแก้ปัญหาต่อไปนี้เพื่อให้ได้ผลลัพธ์ที่ต้องการ หากคุณเป็นคนรัก Java-Naming-Conventions คำแนะนำของฉันคือหยุดอ่านที่นี่ ...

การมีคลาสเช่นนี้การกำหนดค่าคงที่จัดกลุ่มตามคลาสว่างเพื่อสร้างลำดับชั้น:

public class PERMISSION{
    public static class PAGE{
       public static final Long SEE = 1L; 
       public static final Long EDIT = 2L; 
       public static final Long DELETE = 4L; 
       ...
    }
}

สามารถใช้จากภายใน java PERMISSION.PAGE.SEEเพื่อดึงค่า1L

เพื่อให้บรรลุความเป็นไปได้ในการเข้าถึงที่เรียบง่ายจากภายใน EL-Expressions ฉันได้ทำสิ่งนี้: (หากมีการเข้ารหัส - เขาหวังว่าจะให้อภัยฉัน: D)

@Named(value="PERMISSION")
public class PERMISSION{
    public static class PAGE{
       public static final Long SEE = 1L; 
       public static final Long EDIT = 2L; 
       public static final Long DELETE = 4L; 
       ...

       //EL Wrapper
       public Long getSEE(){
           return PAGE.SEE;
       }

       public Long getEDIT(){
           return PAGE.EDIT;
       }

       public Long getDELETE(){
           return PAGE.DELETE;
       }
    }

    //EL-Wrapper
    public PAGE getPAGE() {
        return new PAGE();
    }
}

ในที่สุด EL-Expression ในการเข้าถึงสิ่งเดียวกันLongจะกลายเป็น: #{PERMISSION.PAGE.SEE}- ความเท่าเทียมกันสำหรับ Java และ EL-Access ฉันรู้ว่าสิ่งนี้ไม่ได้อยู่ในรูปแบบใด ๆ แต่มันก็ใช้ได้ดี


2

@Bozho ให้คำตอบที่ยอดเยี่ยมแล้ว

คุณมักจะวางค่าคงที่ประเภทนี้ไว้ในวัตถุ Configuration (ซึ่งมี getters และ setters) ในบริบท servlet และเข้าถึงด้วย $ {applicationScope.config.url}

อย่างไรก็ตามฉันรู้สึกว่าจำเป็นต้องมีตัวอย่างดังนั้นจึงมีความชัดเจนมากขึ้นและเผื่อเวลาให้ใครบางคน

@Component
public Configuration implements ServletContextAware {
    private String addressURL = Addresses.URL;

    // Declare other properties if you need as also add corresponding
    // getters and setters

    public String getAddressURL() {
        return addressURL;
    }

    public void setServletContext(ServletContext servletContext) {
        servletContext.setAttribute("config", this);
    }
}

0

มีวิธีแก้ปัญหาที่ไม่ตรงกับที่คุณต้องการ แต่ช่วยให้คุณใช้งานได้เกือบจะเหมือนกันกับการสัมผัสสคริปต์เล็ตในลักษณะที่ค่อนข้างน้อย คุณสามารถใช้ scriptlet เพื่อใส่ค่าลงในตัวแปร JSTL และใช้โค้ด JSTL ที่สะอาดในภายหลังในเพจ

<%@ taglib prefix="c"       uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page import="com.whichever.namespace.Addresses" %>
<c:set var="ourUrl" value="<%=Addresses.URL%>"/>
<c:if test='${"http://www.google.com" eq ourUrl}'>
   Google is our URL!
</c:if>

1
ฉันไม่เห็นว่าเหตุใดจึงมีการโหวตลดลง นี่เป็นรูปแบบเดียวกับตัวเลือก # 3 ใน: stackoverflow.com/a/16692821/274677
Marcus Junius Brutus
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.