Wie referenziere ich Konstanten in EL?

106

Wie referenzieren Sie eine Konstante mit EL auf einer JSP-Seite?

Ich habe eine Schnittstelle Addressesmit einer Konstanten namens URL. Ich weiß, dass ich es mit einem Scriplet referenzieren kann, indem ich gehe: <%=Addresses.URL%>Aber wie mache ich das mit EL?

Tau-Neutrino
quelle

Antworten:

155

EL 3.0 oder neuer

Wenn Sie bereits mit Java EE 7 / EL 3.0 arbeiten, @page importimportiert das auch Klassenkonstanten im EL-Bereich.

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

Dies wird unter der Decke über importiert ImportHandler#importClass()und ist verfügbar als ${YourConstants.FOO}.

Beachten Sie, dass alle java.lang.*Klassen sind bereits implizit importiert und verfügbar wie so ${Boolean.TRUE}und ${Integer.MAX_VALUE}. Dies erfordert nur einen neueren Java EE 7-Containerserver, da frühere Versionen Fehler aufwiesen. ZB GlassFish 4.0 und Tomcat 8.0.0-1x schlagen fehl, aber GlassFish 4.1+ und Tomcat 8.0.2x + funktionieren. Und Sie müssen unbedingt sicherstellen, dass Ihr web.xmlKonto der neuesten vom Server unterstützten Servlet-Version entspricht. Daher web.xmlfunktioniert mit einem Servlet 2.5 oder älter, das als konform deklariert ist, keine der Servlet 3.0+ Funktionen.

Beachten Sie auch, dass diese Funktion nur in JSP und nicht in Facelets verfügbar ist. Im Fall von JSF + Facelets verwenden Sie OmniFaces am<o:importConstants> besten wie folgt :

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

Oder fügen Sie einen EL-Kontext-Listener hinzu, der ImportHandler#importClass()wie folgt aufruft :

@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 oder älter

Dies ist in EL 2.2 und älter nicht möglich. Es gibt verschiedene Alternativen:

  1. Fügen Sie sie in ein Feld ein, Map<String, Object>das Sie in den Anwendungsbereich aufgenommen haben. In EL sind Kartenwerte auf die übliche javabäische Weise über ${map.key}oder zugänglich ${map['key.with.dots']}.

  2. Verwendung <un:useConstants>der Unstandard taglib (maven2 repo hier ):

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

    Auf diese Weise sind sie auf die übliche javabäische Weise zugänglich ${constants.FOO}.

  3. Verwenden Sie Javaranch's CCC, <ccc:constantsMap> wie irgendwo am Ende dieses Artikels beschrieben .

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

    Auf diese Weise sind sie auch auf die übliche javabäische Weise zugänglich ${constants.FOO}.

  4. Wenn Sie JSF2 verwenden, dann könnten Sie <o:importConstants>von OmniFaces .

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

    Auf diese Weise sind sie auch auf die übliche javabäische Weise zugänglich #{YourConstants.FOO}.

  5. Erstellen Sie eine Wrapper-Klasse, die sie über Getter-Methoden im Javabean-Stil zurückgibt.

  6. Erstellen Sie einen benutzerdefinierten EL-Resolver, der zuerst das Vorhandensein einer Konstante überprüft und bei Abwesenheit an den Standard-Resolver delegiert. Andernfalls wird stattdessen der Konstantenwert zurückgegeben.

BalusC
quelle
4
Ich habe diese Frage gefunden, weil ich das gleiche Problem hatte, als ich versuchte, ein statisches Listenfeld mit einem form: options-Tag zu verwenden. Ich konnte es zum Laufen bringen, indem ich einen nicht statischen Getter hinzufügte, der die statische Liste zurückgibt. Es ist ein bisschen klobig, aber hey, das ist JSP-Entwicklung für dich!
spaaarky21
1
Haben Sie ein Beispiel, wie Sie dies für JSF konfigurieren können, wenn die Beans bis zum Frühjahr verwaltet werden? Danke im Voraus.
Untermieter
2
@ Lodge: Ich mache keinen Frühling.
BalusC
2
Lebt das Jakarta- unstandard-taglibProjekt noch? Gibt es eine Alternative?
Davioooh
1
Gibt es eine Möglichkeit, diese Techniken für Aufzählungen zu nutzen?
Niklas Peter
11

Das Folgende gilt nicht für EL im Allgemeinen, sondern nur für SpEL (Spring EL) (getestet mit 3.2.2.RELEASE unter Tomcat 7). Ich denke, es ist erwähnenswert, wenn jemand nach JSP und EL sucht (aber JSP mit Spring verwendet).

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

Normalerweise platzieren Sie diese Art von Konstanten in einem ConfigurationObjekt (das Getter und Setter enthält) im Servlet-Kontext und greifen mit darauf zu${applicationScope.config.url}

Bozho
quelle
Ein bisschen ein Anfänger hier, wenn es um JSPs geht - könnten Sie das genauer erklären?
Tau-Neutrino
1
@ Tau-Neutrino: Es ist eigentlich einfach. Erstellen Sie eine Klasse mit urleiner String-Eigenschaft, benennen Sie sie Configuration, instanziieren Sie sie und setzen urlSie sie auf das , was Sie möchten. Danach setzen Sie das ConfigurationObjekt in ServletContext. Mach so etwas wie , servletContext.setAttribute("config", config). Und los geht's.
Adeel Ansari
Was ist der Unterschied zwischen Ihrer vorgeschlagenen Lösung und dem einfachen Hinzufügen der Konstante als Attribut von ServletContext? Können Sie die Konstanten nur ordentlicher klassifizieren? zB: applicationScope.config.urlvs applicationScope.url.
Theyuv
7

Das kannst du nicht. Es folgt der Java Bean-Konvention. Sie müssen also einen Getter dafür haben.

Adeel Ansari
quelle
5

Auf statische Eigenschaften kann in EL nicht zugegriffen werden. Die Problemumgehung, die ich verwende, besteht darin, eine nicht statische Variable zu erstellen, die sich dem statischen Wert zuweist.

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

Ich benutze Lombok, um den Getter und Setter zu generieren, also ist es ziemlich gut. Ihre EL sieht so aus:

${bean.manager_role}

Vollständiger Code unter http://www.ninthavenue.com.au/java-static-constants-in-jsp-and-jsf-el

Roger Keays
quelle
5

Ich implementierte wie:

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

Im nächsten Schritt fügen Sie die Instanz dieser Klasse in servlerContext ein

public class ApplicationInitializer implements ServletContextListener {


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

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

Listener zu web.xml hinzufügen

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

Zugriff in jsp

${Constants.PAGE_SIZE}
Serhii Bohutskyi
quelle
4

Ich definiere gleich zu Beginn eine Konstante in meinem JSP:

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

Ich füge die Core-Taglib in meine JSP ein:

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

Dann stelle ich EL die Konstante mit folgender Anweisung zur Verfügung:

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

Jetzt kann ich es später verwenden. Hier ein Beispiel, in dem der Wert nur als HTML-Kommentar für Debugging-Zwecke geschrieben wird:

<!-- ${URI} -->

Mit Ihrer konstanten Klasse können Sie einfach Ihre Klasse importieren und die Konstanten lokalen Variablen zuweisen. Ich weiß, dass meine Antwort eine Art schneller Hack ist, aber die Frage taucht auch auf, wenn man Konstanten direkt in der JSP definieren möchte.

koppor
quelle
1
lol Warum nicht Scriptlets direkt verwenden, wenn Sie auf diese Weise die EL-Variablen initialisieren?
Navin
Drei Zeilen oben sind ein Durcheinander und reinigen dann EL im Rest der JSP ^^.
Koppor
1
@ Koppoor Ich denke schon. Ich werde nur verwenden <%=URI%>: P
Navin
1
Ich hatte einen Ort, an dem ein Direct <%=URI%>nicht funktionierte, aber diese Technik tat es.
Englebart
3

Ja, du kannst. Sie benötigen ein benutzerdefiniertes Tag (wenn Sie es nicht woanders finden können). Ich habe das getan:

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

und das Tag heißt:

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

Alle öffentlichen statischen endgültigen Variablen werden in eine Map eingefügt, die durch ihren Java-Namen indiziert ist

public static final int MY_FIFTEEN = 15;

dann wird das Tag dies in eine Ganzzahl einschließen und Sie können es in einer JSP referenzieren:

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

und du musst keine Getter schreiben!

Tim Sabin
quelle
3

Sie können. Versuchen Sie es auf folgende Weise

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

Getestet auf TomCat 7 und Java6

Dmytro Boichenko
quelle
3
Das sieht aus wie SpEL und nicht wie EL. Irre ich mich Würde das auch in einem älteren Tomcat5.5 funktionieren?
Pytry
2

Selbst wenn ich weiß, dass es etwas spät ist und wenn ich weiß, dass dies ein kleiner Hack ist, habe ich die folgende Lösung verwendet, um das gewünschte Ergebnis zu erzielen. Wenn Sie ein Liebhaber von Java-Namenskonventionen sind, ist mein Rat, hier nicht mehr zu lesen ...

Eine solche Klasse haben, Konstanten definieren, nach leeren Klassen gruppiert, um eine Art Hierarchie zu erstellen:

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

kann aus Java heraus verwendet werden PERMISSION.PAGE.SEE, um den Wert abzurufen1L

Um eine ähnliche Zugriffsmöglichkeit innerhalb von EL-Expressions zu erreichen, habe ich Folgendes getan: (Wenn es einen Codierungsgott gibt - er könnte mir hoffentlich vergeben: 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();
    }
}

Schließlich wird der EL-Ausdruck für den Zugriff auf dasselbe Long: #{PERMISSION.PAGE.SEE}- Gleichheit für Java und EL-Access. Ich weiß, dass dies keine Konvention ist, aber es funktioniert einwandfrei.

dognose
quelle
2

@Bozho lieferte bereits eine gute Antwort

Normalerweise platzieren Sie diese Art von Konstanten in einem Konfigurationsobjekt (das Getter und Setter enthält) im Servlet-Kontext und greifen mit $ {applicationScope.config.url} darauf zu.

Ich bin jedoch der Meinung, dass ein Beispiel benötigt wird, um ein bisschen mehr Klarheit zu schaffen und jemandem Zeit zu sparen

@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);
    }
}
Lunohodov
quelle
0

Es gibt eine Problemumgehung, die nicht genau Ihren Wünschen entspricht, mit der Sie jedoch fast genauso aktiv werden können, indem Sie Scriptlets auf sehr minimale Weise berühren. Sie können das Scriptlet verwenden, um einen Wert in eine JSTL-Variable einzufügen und später auf der Seite sauberen JSTL-Code zu verwenden.

<%@ 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>
Artem
quelle
1
Ich verstehe nicht, warum dies abgelehnt wurde. Dies ist das gleiche Muster wie Option 3 in: stackoverflow.com/a/16692821/274677
Marcus Junius Brutus