¿Cómo se hace referencia a una constante con EL en una página JSP?
Tengo una interfaz Addresses
con una constante llamada URL
. Sé que puedo hacer referencia a él con un scriplet yendo:, <%=Addresses.URL%>
pero ¿cómo hago esto usando EL?
¿Cómo se hace referencia a una constante con EL en una página JSP?
Tengo una interfaz Addresses
con una constante llamada URL
. Sé que puedo hacer referencia a él con un scriplet yendo:, <%=Addresses.URL%>
pero ¿cómo hago esto usando EL?
Respuestas:
Si ya está en Java EE 7 / EL 3.0, entonces @page import
también importará constantes de clase en el alcance EL.
<%@ page import="com.example.YourConstants" %>
Esto debajo de las cubiertas se importará a través de ImportHandler#importClass()
y estará disponible como ${YourConstants.FOO}
.
Tenga en cuenta que todas las java.lang.*
clases ya están implícitamente importadas y disponibles como tal ${Boolean.TRUE}
y ${Integer.MAX_VALUE}
. Esto solo requiere un servidor de contenedor Java EE 7 más reciente, ya que las primeras versiones tenían errores en esto. Por ejemplo, GlassFish 4.0 y Tomcat 8.0.0-1x fallan, pero GlassFish 4.1+ y Tomcat 8.0.2x + funcionan. Y debe asegurarse absolutamente de que web.xml
se declara que cumple con la última versión de servlet admitida por el servidor. Por lo tanto, con un web.xml
Servlet 2.5 declarado conforme o anterior, ninguna de las características de Servlet 3.0+ funcionará.
También tenga en cuenta que esta función solo está disponible en JSP y no en Facelets. En el caso de JSF + Facelets, su mejor opción<o:importConstants>
es utilizar OmniFaces como se muestra a continuación:
<o:importConstants type="com.example.YourConstants" />
O agregando un oyente de contexto EL que llama de la ImportHandler#importClass()
siguiente manera:
@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");
}
});
}
}
Esto no es posible en EL 2.2 y versiones anteriores. Existen varias alternativas:
Colóquelos en el Map<String, Object>
que puso en el ámbito de la aplicación. En EL, los valores del mapa son accesibles de la forma habitual de Java por ${map.key}
o ${map['key.with.dots']}
.
El uso <un:useConstants>
de la unstandard taglib (maven2 Repo aquí ):
<%@ taglib uri="http://jakarta.apache.org/taglibs/unstandard-1.0" prefix="un" %>
<un:useConstants className="com.example.YourConstants" var="constants" />
De esta manera, son accesibles de la forma habitual en Java ${constants.FOO}
.
Utilice CCC de Javaranch <ccc:constantsMap>
como se describe en alguna parte al final de este artículo .
<%@ taglib uri="http://bibeault.org/tld/ccc" prefix="ccc" %>
<ccc:constantsMap className="com.example.YourConstants" var="constants" />
De esta forma, también son accesibles de la forma habitual en Java ${constants.FOO}
.
Si está utilizando JSF2, entonces se podría utilizar <o:importConstants>
de OmniFaces .
<html ... xmlns:o="http://omnifaces.org/ui">
<o:importConstants type="com.example.YourConstants" />
De esta forma, también son accesibles de la forma habitual en Java #{YourConstants.FOO}
.
Cree una clase contenedora que los devuelva a través de métodos getter de estilo Javabean.
Cree un resolutor EL personalizado que primero escanee la presencia de una constante y, si está ausente, luego delegue al resolutor predeterminado; de lo contrario, devuelve el valor constante.
unstandard-taglib
Sigue vivo el proyecto de Yakarta ? hay alguna alternativa?
Lo siguiente no se aplica a EL en general, sino a SpEL (Spring EL) solo (probado con 3.2.2.RELEASE en Tomcat 7). Creo que vale la pena mencionarlo aquí en caso de que alguien busque JSP y EL (pero usa JSP con Spring).
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<spring:eval var="constant" expression="T(com.example.Constants).CONSTANT"/>
Por lo general, coloca este tipo de constantes en un Configuration
objeto (que tiene captadores y establecedores) en el contexto del servlet y accede a ellas con${applicationScope.config.url}
url
una propiedad String, asígnele un nombre Configuration
, cree una instancia y establezca el valor url
que desee. Después de eso, coloque ese Configuration
objeto ServletContext
. Hacer algo así, servletContext.setAttribute("config", config)
. Y ahí tienes.
ServletContext
? ¿Es solo que puede clasificar las constantes de manera más ordenada? por ejemplo: applicationScope.config.url
vs applicationScope.url
.
No puedes. Sigue la convención de Java Bean. Así que debes tener un captador para ello.
Las propiedades estáticas no son accesibles en EL. La solución alternativa que utilizo es crear una variable no estática que se asigne al valor estático.
public final static String MANAGER_ROLE = 'manager';
public String manager_role = MANAGER_ROLE;
Yo uso lombok para generar el getter y setter, así que está bastante bien. Su EL se ve así:
${bean.manager_role}
Código completo en http://www.ninthavenue.com.au/java-static-constants-in-jsp-and-jsf-el
Implementé como:
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;
}
}
El siguiente paso coloca la instancia de esta clase en servlerContext
public class ApplicationInitializer implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
sce.getServletContext().setAttribute("Constants", new JspConstants());
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
agregar oyente a web.xml
<listener>
<listener-class>com.example.ApplicationInitializer</listener-class>
</listener>
acceso en jsp
${Constants.PAGE_SIZE}
Estoy definiendo una constante en mi jsp desde el principio:
<%final String URI = "http://www.example.com/";%>
Incluyo el taglib principal en mi JSP:
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
Luego, pongo la constante a disposición de EL mediante la siguiente declaración:
<c:set var="URI" value="<%=URI%>"></c:set>
Ahora puedo usarlo más tarde. Aquí un ejemplo, donde el valor simplemente se escribe como comentario HTML para fines de depuración:
<!-- ${URI} -->
Con su clase constante, puede importar su clase y asignar las constantes a las variables locales. Sé que mi respuesta es una especie de truco rápido, pero la pregunta también surge cuando uno quiere definir constantes directamente en el JSP.
<%=URI%>
: P
<%=URI%>
no funcionaba, pero esta técnica sí.
Sí tu puedes. Necesita una etiqueta personalizada (si no puede encontrarla en otro lugar). He hecho esto:
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;
}
}
y la etiqueta se llama:
<yourLib:constMap path="path.to.your.constantClass" var="consts" />
Todas las variables finales estáticas públicas se colocarán en un mapa indexado por su nombre de Java, por lo que si
public static final int MY_FIFTEEN = 15;
luego la etiqueta lo envolverá en un entero y puede hacer referencia a él en un JSP:
<c:if test="${consts['MY_FIFTEEN'] eq 15}">
¡y no tienes que escribir getters!
Usted puede. Prueba de la siguiente manera
#{T(com.example.Addresses).URL}
Probado en TomCat 7 y java6
Incluso sabiendo que es un poco tarde, e incluso sabiendo que esto es un pequeño truco, utilicé la siguiente solución para lograr el resultado deseado. Si eres un amante de las convenciones de nombres de Java, mi consejo es que dejes de leer aquí ...
Tener una clase como esta, definiendo constantes, agrupadas por clases vacías para crear una especie de jerarquía:
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;
...
}
}
se puede usar desde java PERMISSION.PAGE.SEE
para recuperar el valor1L
Para lograr una posibilidad de acceso similar desde dentro de EL-Expressions, hice esto: (Si hay un dios codificador, con suerte podría perdonarme: 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();
}
}
finalmente, la expresión EL para acceder a la misma se Long
convierte en: #{PERMISSION.PAGE.SEE}
- igualdad para Java y EL-Access. Sé que esto está fuera de cualquier convención, pero funciona perfectamente bien.
@Bozho ya dio una gran respuesta
Por lo general, coloca este tipo de constantes en un objeto de configuración (que tiene captadores y definidores) en el contexto del servlet y accede a ellas con $ {applicationScope.config.url}
Sin embargo, creo que se necesita un ejemplo, por lo que aporta un poco más de claridad y ahorra tiempo a alguien.
@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);
}
}
Hay una solución que no es exactamente lo que desea, pero le permite activar casi lo mismo tocando scriptlets de una manera bastante mínima. Puede usar scriptlet para poner valor en una variable JSTL y usar código JSTL limpio más adelante en la página.
<%@ 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>