web-dev-qa-db-fra.com

Comment référencer les constantes dans EL?

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

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

102
tau-neutrino

EL 3.0 ou plus récent

Si vous êtes déjà sur Java EE 7/EL 3.0, le @page import Importera également les constantes de classe dans l'étendue EL.

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

Cela sera sous les couvertures importé via ImportHandler#importClass() et sera disponible sous la forme ${YourConstants.FOO}.

Notez que toutes les classes Java.lang.* Sont déjà implicitement importées et disponibles comme ceci ${Boolean.TRUE} Et ${Integer.MAX_VALUE}. Cela nécessite seulement un Java serveur de conteneur EE 7 plus récent), car les premières versions contenaient 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.xml Est déclaré conforme à la dernière version de servlet prise en charge par le serveur. Ainsi, avec un web.xml Déclaré conforme au servlet 2.5 ou plus ancien, aucun servlet 3.0+ fonctionnalités fonctionneront.

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

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

Ou ajouter 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 ancien

Ceci est impossible dans EL 2.2 et les versions antérieures. Il y a plusieurs alternatives:

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

  2. Utilisez <un:useConstants> sur le Non standard 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 javabéenne habituelle par ${constants.FOO}.

  3. Utilisez CCC <ccc:constantsMap> De Javaranch 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 javabéenne habituelle par ${constants.FOO}.

  4. Si vous utilisez JSF2, vous pouvez utiliser <o:importConstants> sur 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 javabéenne habituelle par #{YourConstants.FOO}.

  5. Créez une classe wrapper qui les renvoie par le biais de méthodes getter de style javabéen.

  6. Créez un résolveur EL personnalisé qui balaye d'abord la présence d'une constante et, en cas d'absence, puis déléguez au résolveur par défaut, sinon renvoie la valeur constante à la place.

151
BalusC

Ce qui suit ne s'applique pas à EL en général, mais à SpEL (Spring EL) uniquement (testé avec 3.2.2.RELEASE sur Tomcat 7). Je pense qu'il vaut la peine de le mentionner ici si quelqu'un recherche 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"/>
11
anre

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

9
Bozho

Tu ne peux pas. Il suit la convention de bean Java. Il faut donc un getter pour cela.

6
Adeel Ansari

Les propriétés statiques ne sont pas accessibles dans EL. La solution que j’utilise consiste à créer une variable non statique qui s’assigne à 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 assez bien. Votre EL ressemble à ceci:

${bean.manager_role}

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

5
Roger Keays

J'ai mis en place 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;
        }
    }

Prochaine étape, mettre 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 auditeur à web.xml

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

accès en jsp

${Constants.PAGE_SIZE}
5
Serhii Bohutskyi

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 mon JSP:

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

Ensuite, je mets la constante à la disposition de EL en indiquant ce qui suit:

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

Maintenant, je peux l'utiliser plus tard. Voici un exemple où la valeur est simplement écrite en 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 piratage rapide, mais la question se pose aussi lorsqu'on veut définir des constantes directement dans le JSP.

4
koppor

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

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 mappe indexée par leur Java), donc si

public static final int MY_FIFTEEN = 15;

alors la balise englobera 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'avez pas à écrire de getters!

3
Tim Sabin

Vous pouvez. Essayez de suivre

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

Testé sur Tomcat 7 et Java6

3
Dmytro Boichenko

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

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

Cependant, j'estime qu'un exemple est nécessaire afin d'apporter plus de clarté et de laisser le 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);
    }
}
2
lunohodov

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

Avoir une classe comme celle-ci, définissant 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é depuis Java comme PERMISSION.PAGE.SEE pour récupérer la valeur 1L

Pour obtenir une possibilité d'accès similaire depuis EL Expressions, j'ai fait ceci: (S'il y a un dieu codeur, il pourra peut-être me pardonner: 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 permettant d'accéder au même Long devient: #{PERMISSION.PAGE.SEE} - égalité pour Java et EL-Access. Je sais que cela sort de toute convention, mais cela fonctionne parfaitement.

2
dognose

Il existe une solution de contournement qui n’est pas exactement ce que vous souhaitez, mais vous permet d’activer à peu près la même chose en touchant les scriptlets de 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>
0
Artem