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 faire cela en utilisant 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 faire cela en utilisant EL?
Réponses:
Si vous êtes déjà sur Java EE 7 / EL 3.0, alors @page import
importera é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.xml
est déclaré conforme à la dernière version de servlet prise en charge par le serveur. Ainsi, avec un web.xml
qui 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");
}
});
}
}
Cela n'est pas possible dans EL 2.2 et les versions antérieures. Il existe plusieurs alternatives:
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']}
.
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}
.
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}
.
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}
.
Créez une classe wrapper qui les retourne via des méthodes getter de style javanais.
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.
unstandard-taglib
projet jakarta est-il toujours en vie? y a-t-il une alternative?
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"/>
Vous placez généralement ces types de constantes dans un Configuration
objet (qui a des getters et des setters) dans le contexte de servlet, et y accédez avec${applicationScope.config.url}
url
comme propriété String, nommez-la Configuration
, instanciez-la et définissez le url
sur ce que vous voulez. Après cela, définissez cet Configuration
objet ServletContext
. Faites quelque chose comme, servletContext.setAttribute("config", config)
. Et voilà.
ServletContext
? Est-ce simplement que vous pouvez classer les constantes plus précisément? par exemple: applicationScope.config.url
vs applicationScope.url
.
Vous ne pouvez pas. Il suit la convention Java Bean. Vous devez donc avoir un getter pour cela.
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
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}
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.
<%=URI%>
: P
<%=URI%>
ne fonctionnait pas, mais cette technique fonctionnait.
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!
Vous pouvez. Essayez de la manière suivante
#{T(com.example.Addresses).URL}
Testé sur TomCat 7 et java6
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.SEE
pour 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 Long
devient: #{PERMISSION.PAGE.SEE}
- l'égalité pour Java et EL-Access. Je sais que c'est hors de toute convention, mais cela fonctionne parfaitement bien.
@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);
}
}
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>