Come fare riferimento alle costanti in EL?


106

Come si fa riferimento a costanti con EL su una pagina JSP?

Ho un'interfaccia Addressescon una costante denominata URL. So di poterlo fare riferimento con uno scriplet andando:, <%=Addresses.URL%>ma come posso farlo usando EL?

Risposte:


156

EL 3.0 o più recente

Se sei già su Java EE 7 / EL 3.0, @page importimporterà anche le costanti di classe nell'ambito EL.

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

Questo sotto le coperte verrà importato tramite ImportHandler#importClass()e sarà disponibile come file ${YourConstants.FOO}.

Nota che tutte le java.lang.*classi sono già implicitamente importate e disponibili in questo modo ${Boolean.TRUE}e ${Integer.MAX_VALUE}. Ciò richiede solo un server contenitore Java EE 7 più recente poiché le prime versioni presentavano bug in questo. Ad esempio, GlassFish 4.0 e Tomcat 8.0.0-1x non riesce, ma GlassFish 4.1+ e Tomcat 8.0.2x + funzionano. E devi assicurarti assolutamente che il tuo web.xmlsia dichiarato conforme all'ultima versione del servlet supportata dal server. Pertanto, con un web.xmlServlet dichiarato conforme 2.5 o precedente, nessuna delle funzionalità di Servlet 3.0+ funzionerà.

Notare inoltre che questa funzione è disponibile solo in JSP e non in Facelets. In caso di JSF + Facelets, la soluzione migliore è utilizzare OmniFaces<o:importConstants> come di seguito:

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

O aggiungendo un listener di contesto EL che chiama ImportHandler#importClass()come di seguito:

@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 o precedente

Questo non è possibile in EL 2.2 e versioni precedenti. Esistono diverse alternative:

  1. Mettili in una Map<String, Object>che inserisci nell'ambito dell'applicazione. In EL, i valori della mappa sono accessibili nel solito modo javabeano con ${map.key}o ${map['key.with.dots']}.

  2. L'uso <un:useConstants>del Unstandard taglib (maven2 Repo qui ):

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

    In questo modo sono accessibili nel solito modo javabeano ${constants.FOO}.

  3. Usa il CCC <ccc:constantsMap> di Javaranch come descritto da qualche parte in fondo a questo articolo .

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

    In questo modo sono accessibili anche nel solito modo javabeano ${constants.FOO}.

  4. Se stai usando JSF2, allora si potrebbe utilizzare <o:importConstants>di OmniFaces .

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

    In questo modo sono accessibili anche nel solito modo javabeano #{YourConstants.FOO}.

  5. Crea una classe wrapper che li restituisca tramite metodi getter in stile Javabean.

  6. Creare un resolver EL personalizzato che prima scansiona la presenza di una costante e, se assente, quindi delegato al resolver predefinito, altrimenti restituisce invece il valore della costante.


4
Ho trovato questa domanda perché stavo riscontrando lo stesso problema quando cercavo di utilizzare un campo Elenco statico con un tag form: options. Sono stato in grado di farlo funzionare aggiungendo un getter non statico che restituisce l'elenco statico. È un po 'complicato ma hey, questo è lo sviluppo di JSP per te!
spaaarky 21

1
Hai qualche esempio su come configurarlo per JSF se i bean sono gestiti entro la primavera? Grazie in anticipo.
Lodger

2
@Lodger: non faccio la primavera.
BalusC

2
Il unstandard-taglibprogetto jakarta è ancora vivo? c'è qualche alternativa?
davioooh

1
C'è un modo per sfruttare queste tecniche per le enumerazioni?
Niklas Peter

11

Quanto segue non si applica a EL in generale, ma solo a SpEL (Spring EL) (testato con 3.2.2.RELEASE su Tomcat 7). Penso che valga la pena menzionarlo qui nel caso in cui qualcuno cerchi JSP ed EL (ma usa JSP con Spring).

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

9

Di solito si inseriscono questi tipi di costanti in un Configurationoggetto (che ha getter e setter) nel contesto servlet e si accede ad essi con${applicationScope.config.url}


Un po 'un principiante qui quando si tratta di jsp - potresti spiegarlo in modo più completo?
tau-neutrino

1
@ tau-neutrino: è semplice in realtà. Crea una classe con urluna proprietà String Configuration, nominala, crea un'istanza e imposta urlcome preferisci. Dopo di che imposta Configurationquell'oggetto ServletContext. Fare qualcosa di simile, servletContext.setAttribute("config", config). Ed eccoti qui.
Adeel Ansari

Qual è la differenza tra la soluzione proposta e la semplice aggiunta della costante come attributo di ServletContext? È solo che puoi classificare le costanti in modo più ordinato? ad esempio: applicationScope.config.urlvs applicationScope.url.
theyuv

7

Non puoi. Segue la convenzione Java Bean. Quindi devi avere un getter per questo.


5

Le proprietà statiche non sono accessibili in EL. La soluzione alternativa che utilizzo è creare una variabile non statica che si assegna al valore statico.

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

Uso lombok per generare il getter e il setter, quindi va bene così. Il tuo EL ha questo aspetto:

${bean.manager_role}

Codice completo su http://www.ninthavenue.com.au/java-static-constants-in-jsp-and-jsf-el


5

Ho implementato come:

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

Il passaggio successivo inserisce l'istanza di questa classe in servlerContext

public class ApplicationInitializer implements ServletContextListener {


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

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

aggiungi listener a web.xml

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

accesso in jsp

${Constants.PAGE_SIZE}

4

Sto definendo una costante nel mio jsp all'inizio:

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

Includo il core taglib nel mio JSP:

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

Quindi, metto la costante a disposizione di EL con la seguente dichiarazione:

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

Ora posso usarlo in seguito. Ecco un esempio, in cui il valore è scritto solo come commento HTML a scopo di debug:

<!-- ${URI} -->

Con la tua classe costante, puoi semplicemente importare la tua classe e assegnare le costanti alle variabili locali. So che la mia risposta è una sorta di hack veloce, ma la domanda sorge anche quando si desidera definire le costanti direttamente nel JSP.


1
lol perché non utilizzare direttamente gli scriptlet se è così che si inizializzano le variabili EL?
Navin

Tre linee in alto sono un disastro e poi pulire EL per tutto il resto del JSP ^^.
koppor

1
@koppoor credo di sì. Userò solo <%=URI%>: P
Navin

1
Avevo un posto in cui una diretta <%=URI%>non funzionava, ma questa tecnica funzionava.
englebart

3

Si, puoi. Hai bisogno di un tag personalizzato (se non riesci a trovarlo da qualche altra parte). Ho fatto questo:

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

e il tag si chiama:

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

Tutte le variabili finali statiche pubbliche verranno inserite in una mappa indicizzata dal loro nome Java, quindi se

public static final int MY_FIFTEEN = 15;

quindi il tag lo racchiuderà in un numero intero e puoi fare riferimento ad esso in un JSP:

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

e non devi scrivere getter!


3

Puoi. Prova nel modo seguente

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

Testato su TomCat 7 e java6


3
Sembra SpEL e non EL. Mi sbaglio? Inoltre, funzionerebbe in un vecchio Tomcat5.5?
Pytry

2

Anche sapendo che è un po 'tardi, e anche sapendo che questo è un piccolo trucco, ho usato la seguente soluzione per ottenere il risultato desiderato. Se sei un amante delle convenzioni di denominazione Java, il mio consiglio è di smettere di leggere qui ...

Avere una classe come questa, che definisce le costanti, raggruppate per classi vuote per creare una sorta di gerarchia:

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

può essere utilizzato da java PERMISSION.PAGE.SEEper recuperare il valore1L

Per ottenere una possibilità di accesso simile da EL-Expressions, ho fatto questo: (Se c'è un dio della codifica - si spera che possa perdonarmi: 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();
    }
}

infine, l'espressione EL per accedere allo stesso Longdiventa: #{PERMISSION.PAGE.SEE}- uguaglianza per Java ed EL-Access. So che è fuori dalle convenzioni, ma funziona perfettamente.


2

@Bozho ha già fornito un'ottima risposta

Di solito si inseriscono questi tipi di costanti in un oggetto Configuration (che ha getter e setter) nel contesto servlet e si accede ad essi con $ {applicationScope.config.url}

Tuttavia, sento che è necessario un esempio, quindi porta un po 'più di chiarezza e risparmia tempo a qualcuno

@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

C'è una soluzione alternativa che non è esattamente ciò che desideri, ma ti consente di attivarti quasi allo stesso modo toccando gli scriptlet in modo minimale. È possibile utilizzare lo scriptlet per inserire un valore in una variabile JSTL e utilizzare il codice JSTL pulito più avanti nella pagina.

<%@ 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
Non vedo perché questo è stato votato contro. Questo è lo stesso schema dell'opzione n. 3 in: stackoverflow.com/a/16692821/274677
Marcus Junius Brutus
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.