Comment référencer des constantes en EL?

106

Comment référencer une constante avec EL sur une page JSP?

J'ai une interface Addressesavec une constante nommée URL. Je sais que je peux le référencer avec un scriplet en allant:, <%=Addresses.URL%>mais comment faire cela en utilisant EL?

tau-neutrino
la source

Réponses:

156

EL 3.0 ou plus récent

Si vous êtes déjà sur Java EE 7 / EL 3.0, alors @page importimportera également les constantes de classe dans la portée EL.

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

Ce sera sous les couvertures importé via ImportHandler#importClass()et disponible en tant que ${YourConstants.FOO}.

Notez que toutes les java.lang.*classes sont déjà implicitement importées et disponibles comme tel ${Boolean.TRUE}et tel ${Integer.MAX_VALUE}. Cela ne nécessite qu'un serveur de conteneur Java EE 7 plus récent car les premières versions présentaient des bogues. Par exemple, GlassFish 4.0 et Tomcat 8.0.0-1x échouent, mais GlassFish 4.1+ et Tomcat 8.0.2x + fonctionnent. Et vous devez absolument vous assurer que votre web.xmlest déclaré conforme à la dernière version de servlet prise en charge par le serveur. Ainsi, avec un web.xmlqui est déclaré conforme Servlet 2.5 ou plus ancien, aucune des fonctionnalités Servlet 3.0+ ne fonctionnera.

Notez également que cette fonctionnalité n'est disponible que dans JSP et non dans Facelets. Dans le cas de JSF + Facelets, votre meilleur pari est d'utiliser OmniFaces<o:importConstants> comme ci-dessous:

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

Ou en ajoutant un écouteur de contexte EL qui appelle ImportHandler#importClass()comme ci-dessous:

@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 ou plus

Cela n'est pas possible dans EL 2.2 et les versions antérieures. Il existe plusieurs alternatives:

  1. Mettez-les dans un Map<String, Object>que vous mettez dans la portée de l'application. En EL, les valeurs de la carte sont accessibles de la manière javanaise habituelle par ${map.key}ou ${map['key.with.dots']}.

  2. Utilisation <un:useConstants>du Unstandard taglib (maven2 repo ici ):

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

    De cette façon, ils sont accessibles de la manière javanaise habituelle ${constants.FOO}.

  3. Utilisez le CCC de Javaranch <ccc:constantsMap>comme décrit quelque part au bas de cet article .

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

    De cette façon, ils sont également accessibles de la manière javanaise habituelle ${constants.FOO}.

  4. Si vous utilisez JSF2, vous pouvez utiliser <o:importConstants>des OmniFaces .

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

    De cette façon, ils sont également accessibles de la manière javanaise habituelle #{YourConstants.FOO}.

  5. Créez une classe wrapper qui les retourne via des méthodes getter de style javanais.

  6. Créez un résolveur EL personnalisé qui scanne d'abord la présence d'une constante et s'il est absent, déléguez ensuite au résolveur par défaut, sinon renvoie la valeur de la constante à la place.

BalusC
la source
4
J'ai trouvé cette question parce que j'avais le même problème en essayant d'utiliser un champ de liste statique avec une balise form: options. J'ai pu le faire fonctionner en ajoutant un getter non statique qui renvoie la liste statique. C'est un peu bavard mais bon, c'est le développement JSP pour toi!
spaaarky21
1
Avez-vous un exemple comment configurer cela pour JSF si les beans sont gérés par spring? Merci d'avance.
Lodger
2
@Lodger: Je ne fais pas le printemps.
BalusC
2
Le unstandard-taglibprojet jakarta est-il toujours en vie? y a-t-il une alternative?
davioooh
1
Existe-t-il un moyen d'exploiter ces techniques pour les énumérations?
Niklas Peter
11

Ce qui suit ne s'applique pas à EL en général, mais plutôt à SpEL (Spring EL) uniquement (testé avec 3.2.2.RELEASE sur Tomcat 7). Je pense qu'il vaut la peine de le mentionner ici au cas où quelqu'un chercherait JSP et EL (mais utilise JSP avec Spring).

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

Vous placez généralement ces types de constantes dans un Configurationobjet (qui a des getters et des setters) dans le contexte de servlet, et y accédez avec${applicationScope.config.url}

Bozho
la source
Un peu novice ici en ce qui concerne les jsp - pourriez-vous expliquer cela plus en détail?
tau-neutrino
1
@ tau-neutrino: C'est simple en fait. Créez une classe avec urlcomme propriété String, nommez-la Configuration, instanciez-la et définissez le urlsur ce que vous voulez. Après cela, définissez cet Configurationobjet ServletContext. Faites quelque chose comme, servletContext.setAttribute("config", config). Et voilà.
Adeel Ansari
Quelle est la différence entre votre solution proposée et le simple ajout de la constante comme attribut du ServletContext? Est-ce simplement que vous pouvez classer les constantes plus précisément? par exemple: applicationScope.config.urlvs applicationScope.url.
theyuv
7

Vous ne pouvez pas. Il suit la convention Java Bean. Vous devez donc avoir un getter pour cela.

Adeel Ansari
la source
5

Les propriétés statiques ne sont pas accessibles dans EL. La solution de contournement que j'utilise est de créer une variable non statique qui s'attribue à la valeur statique.

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

J'utilise lombok pour générer le getter et le setter donc c'est plutôt bien ça. Votre EL ressemble à ceci:

${bean.manager_role}

Code complet sur http://www.ninthavenue.com.au/java-static-constants-in-jsp-and-jsf-el

Roger Keays
la source
5

J'ai implémenté comme:

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

Étape suivante, placez l'instance de cette classe dans servlerContext

public class ApplicationInitializer implements ServletContextListener {


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

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

ajouter un écouteur à web.xml

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

accès dans jsp

${Constants.PAGE_SIZE}
Serhii Bohutskyi
la source
4

Je définis une constante dans mon jsp dès le début:

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

J'inclus le taglib de base dans ma JSP:

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

Ensuite, je mets la constante à la disposition d'EL en suivant la déclaration:

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

Maintenant, je peux l'utiliser plus tard. Voici un exemple, où la valeur est simplement écrite sous forme de commentaire HTML à des fins de débogage:

<!-- ${URI} -->

Avec votre classe constante, vous pouvez simplement importer votre classe et affecter les constantes à des variables locales. Je sais que ma réponse est une sorte de hack rapide, mais la question se pose également lorsque l'on veut définir des constantes directement dans la JSP.

Koppor
la source
1
lol pourquoi ne pas utiliser directement les Scriptlets si c'est ainsi que vous initialisez les variables EL?
Navin
Trois lignes sur le dessus étant en désordre et ensuite nettoyer EL dans le reste de la JSP ^^.
koppor
1
@koppoor, je suppose. Je vais juste utiliser <%=URI%>: P
Navin
1
J'avais un endroit où un direct <%=URI%>ne fonctionnait pas, mais cette technique fonctionnait.
englebart
3

Oui, vous pouvez. Vous avez besoin d'une balise personnalisée (si vous ne la trouvez pas ailleurs). J'ai fait ceci:

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

et la balise s'appelle:

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

Toutes les variables finales statiques publiques seront placées dans une carte indexée par leur nom Java, donc si

public static final int MY_FIFTEEN = 15;

alors la balise encapsulera ceci dans un entier et vous pourrez le référencer dans un JSP:

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

et vous n'êtes pas obligé d'écrire des getters!

Tim Sabin
la source
3

Vous pouvez. Essayez de la manière suivante

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

Testé sur TomCat 7 et java6

Dmytro Boichenko
la source
3
Cela ressemble à SpEL, et non EL. Est-ce que je me trompe? Cela fonctionnerait-il également dans un ancien Tomcat5.5?
Pytry
2

Même en sachant que c'est un peu tard, et même en sachant que c'est un petit hack - j'ai utilisé la solution suivante pour obtenir le résultat souhaité. Si vous êtes un amateur de Java-Naming-Conventions, mon conseil est d'arrêter de lire ici ...

Avoir une classe comme celle-ci, définir des constantes, regroupées par classes vides pour créer une sorte de hiérarchie:

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

peut être utilisé à partir de java PERMISSION.PAGE.SEEpour récupérer la valeur1L

Pour obtenir une possibilité d'accès similaire à partir des expressions EL, j'ai fait ceci: (S'il y a un dieu du codage - il pourrait me pardonner avec un peu de chance: 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();
    }
}

enfin, l'expression EL pour accéder à la même chose Longdevient: #{PERMISSION.PAGE.SEE}- l'égalité pour Java et EL-Access. Je sais que c'est hors de toute convention, mais cela fonctionne parfaitement bien.

dognose
la source
2

@Bozho a déjà fourni une excellente réponse

Vous placez généralement ces types de constantes dans un objet Configuration (qui a des getters et des setters) dans le contexte du servlet, et y accédez avec $ {applicationScope.config.url}

Cependant, je pense qu'un exemple est nécessaire, donc cela apporte un peu plus de clarté et fait gagner du temps à quelqu'un

@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
la source
0

Il existe une solution de contournement qui n'est pas exactement ce que vous voulez, mais qui vous permet d'activer presque de la même manière avec des scriptlets touchants d'une manière assez minimale. Vous pouvez utiliser un scriptlet pour mettre une valeur dans une variable JSTL et utiliser du code JSTL propre plus tard dans la page.

<%@ 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
la source
1
Je ne vois pas pourquoi cela a été voté à la baisse. C'est le même modèle que l'option n ° 3 dans: stackoverflow.com/a/16692821/274677
Marcus Junius Brutus