jsp - ¿Cómo hacer referencia a las constantes en EL?
constants (12)
¿Cómo se hace referencia a las constantes con EL en una página JSP?
Tengo una interfaz Addresses
con una URL
nombre constante. Sé que puedo referenciarlo con un scriplet yendo: <%=Addresses.URL%>
, pero ¿cómo hago esto usando EL?
EL 3.0 o más nuevo
Si ya tiene Java EE 7 / EL 3.0, la @page import
también importará constantes de clase en el alcance de EL.
<%@ page import="com.example.YourConstants" %>
Esto se importará debajo de las cubiertas a través de ImportHandler#importClass()
y estará disponible como ${YourConstants.FOO}
.
Tenga en cuenta que todas las clases de java.lang.*
Ya se importaron implícitamente y están disponibles, como ${Boolean.TRUE}
y ${Integer.MAX_VALUE}
. Esto solo requiere un servidor de contenedor Java EE 7 más reciente ya que las versiones anteriores 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.
Esta instalación solo está disponible en JSP y no en Facelets. En el caso de JSF + Facelets, su mejor opción es usar OmniFaces <o:importConstants>
como se muestra a continuación:
<o:importConstants type="com.example.YourConstants" />
O agregando un oyente de contexto EL que llama a ImportHandler#importClass()
como se muestra a continuación:
@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 más viejo
Esto no es posible en EL 2.2 y anteriores. Hay varias alternativas:
Colóquelos en un
Map<String, Object>
que coloca en el ámbito de la aplicación. En EL, se puede acceder a los valores del mapa de la manera habitual Javabean por${map.key}
o${map[''key.with.dots'']}
.Utilice
<un:useConstants>
del taglib no estándar (repositorio maven2 here ):<%@ taglib uri="http://jakarta.apache.org/taglibs/unstandard-1.0" prefix="un" %> <un:useConstants className="com.example.YourConstants" var="constants" />
De esta forma, son accesibles a la forma Javabean habitual en
${constants.FOO}
.Utilice CCC de Javaranch
<ccc:constantsMap>
como se describe en algún lugar 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 se les puede acceder por el modo Javabean habitual en
${constants.FOO}
.Si está utilizando JSF2, puede usar
<o:importConstants>
de OmniFaces .<html ... xmlns:o="http://omnifaces.org/ui"> <o:importConstants type="com.example.YourConstants" />
De esta forma, también se puede acceder a la forma habitual Javabean por
#{YourConstants.FOO}
.Cree una clase contenedora que los devuelva a través de métodos getter estilo Javabean.
Cree un solucionador EL personalizado que primero escanea la presencia de una constante y si está ausente, luego delegue al resolver predeterminado, de lo contrario devuelve el valor constante en su lugar.
@Bozho ya brindó una gran respuesta
Por lo general, coloca estos tipos de constantes en un objeto de Configuración (que tiene captadores y definidores) en el contexto de servlet y accede a ellos con $ {applicationScope.config.url}
Sin embargo, creo que se necesita un ejemplo para que brinde un poco más de claridad y ahorre 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);
}
}
Estoy definiendo una constante en mi jsp desde el principio:
<%final String URI = "http://www.example.com/";%>
Incluyo el taglib central en mi JSP:
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
Luego, pongo la constante a disposición de EL siguiendo la siguiente declaración:
<c:set var="URI" value="<%=URI%>"></c:set>
Ahora, puedo usarlo más tarde. Aquí un ejemplo, donde el valor se acaba de escribir 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 aumenta cuando uno quiere definir constantes directamente en el JSP.
Existe una solución alternativa que no es exactamente lo que usted quiere, pero que le permite activar casi lo mismo al tocar 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>
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 pone una 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}
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 Java-Naming-Conventions, mi consejo es dejar de leer aquí ...
Tener una clase como esta, definir Constantes, agrupados 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 dentro de java como PERMISSION.PAGE.SEE
para recuperar el valor 1L
Para lograr una posibilidad de acceso similar desde 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 al mismo 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.
Las propiedades estáticas no son accesibles en EL. La solución alternativa que uso es crear una variable no estática que se asigna al valor estático.
public final static String MANAGER_ROLE = ''manager'';
public String manager_role = MANAGER_ROLE;
Yo uso lombok para generar 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
Lo siguiente no se aplica a EL en general, sino a SpEL (Spring EL) solamente (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"/>
No puedes. Sigue la convención de Java Bean. Entonces debes tener un getter para eso.
Por lo general, coloca estos tipos de constantes en un objeto de Configuration
(que tiene captadores y definidores) en el contexto de servlet y accede a ellos con ${applicationScope.config.url}
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 Java, por lo que si
public static final int MY_FIFTEEN = 15;
luego, la etiqueta ajustará esto en un Entero y usted podrá hacer referencia a él en un JSP:
<c:if test="${consts[''MY_FIFTEEN''] eq 15}">
¡y no tienes que escribir getters!
Usted puede. Intenta seguir el camino
#{T(com.example.Addresses).URL}
Probado en TomCat 7 y java6