如何在EL中引用常量?

时间:2010-09-17 04:10:50

标签: jsp constants el

如何在JSP页面上引用EL常量?

我有一个名为Addresses的常量接口URL。我知道我可以用一个scriplet来引用它:<%=Addresses.URL%>,但我怎么用EL做这个呢?

12 个答案:

答案 0 :(得分:150)

EL 3.0或更新版

如果您已经使用Java EE 7 / EL 3.0,那么@page import也将导入EL范围内的类常量。

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

这将通过ImportHandler#importClass()导入,并以${YourConstants.FOO}提供。

请注意,所有java.lang.*类都已隐式导入,并且可以像${Boolean.TRUE}${Integer.MAX_VALUE}一样使用。这只需要一个更新的Java EE 7容器服务器,因为早期版本中存在错误。例如。 GlassFish 4.0和Tomcat 8.0.0-1x失败,但GlassFish 4.1+和Tomcat 8.0.2x +工作正常。并且您需要确保声明web.xml符合服务器支持的最新servlet版本。因此,如果声明符合Servlet 2.5或更早版本的web.xml,则Servlet 3.0+功能都不起作用。

另请注意,此工具仅在JSP中可用,而不在Facelets中。对于JSF + Facelets,最好的办法是使用OmniFaces <o:importConstants>,如下所示:

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

或者添加一个调用ImportHandler#importClass()的EL上下文监听器,如下所示:

@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或更早版

这在EL 2.2及更早版本中可能。有几种选择:

  1. 将它们放入您放入应用程序范围的Map<String, Object>中。在EL中,可以通过${map.key}${map['key.with.dots']}通常的Javabean方式访问地图值。

  2. 使用<un:useConstants>Unstandard taglib(maven2 repo here):

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

    通过这种方式,${constants.FOO}可以使用通常的Javabean方式访问它们。

  3. CCC底部的某处使用Javaranch的this article <ccc:constantsMap>

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

    这样他们也可以通过${constants.FOO}通常的Javabean方式访问。

  4. 如果您使用的是JSF2,则可以使用<o:importConstants>OmniFaces

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

    这样他们也可以通过#{YourConstants.FOO}通常的Javabean方式访问。

  5. 创建一个包装类,通过Javabean样式的getter方法返回它们。

  6. 创建自定义EL解析器,首先扫描常量的存在,如果不存在,则委托默认解析器,否则返回常量值。

答案 1 :(得分:11)

以下内容一般不适用于EL,而是仅适用于SpEL(Spring EL)(在Tomcat 7上使用3.2.2.RELEASE进行测试)。 我认为值得一提的是,如果有人搜索JSP和EL(但是使用JSP和Spring)。

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

答案 2 :(得分:9)

您通常将这些常量放在servlet上下文中的Configuration对象(具有getter和setter)中,并使用${applicationScope.config.url}

访问它们

答案 3 :(得分:6)

你做不到。它遵循Java Bean约定。所以你必须有一个吸气剂。

答案 4 :(得分:5)

EL中无法访问静态属性。我使用的解决方法是创建一个非静态变量,将自己分配给静态值。

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

我使用lombok来生成getter和setter,这样就可以了。你的EL看起来像这样:

${bean.manager_role}

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

的完整代码

答案 5 :(得分:5)

我的实施方式如下:

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

下一步将此类的实例放入servlerContext

public class ApplicationInitializer implements ServletContextListener {


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

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

将监听器添加到web.xml

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

在jsp中访问

${Constants.PAGE_SIZE}

答案 6 :(得分:4)

我在开头就在我的jsp中定义了一个常量:

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

我在我的JSP中包含核心taglib:

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

然后,我通过以下语句使EL继续可用:

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

现在,我可以在以后使用它。这是一个示例,其中值只是作为HTML注释编写以用于调试目的:

<!-- ${URI} -->

使用常量类,您可以导入类并将常量分配给局部变量。我知道我的答案是一种快速破解,但是当人们想直接在JSP中定义常量时,问题也会出现问题。

答案 7 :(得分:3)

是的,你可以。您需要一个自定义标记(如果您在其他地方找不到它)。我做到了这一点:

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

并调用标记:

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

所有公共静态最终变量都将放入由其Java名称索引的Map中,因此如果

public static final int MY_FIFTEEN = 15;

然后标记将它包装在一个Integer中,你可以在JSP中引用它:

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

你不必写吸气剂!

答案 8 :(得分:3)

你可以。尝试以下方式

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

在TomCat 7和java6上测试

答案 9 :(得分:2)

即使知道它有点晚了,甚至知道这有点黑客 - 我使用以下解决方案来达到预期的效果。如果您是Java命名约定的爱好者,我的建议是停止阅读...

拥有这样的类,定义常量,按空类分组以创建层次结构类型:

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

可以在java中用作PERMISSION.PAGE.SEE来检索值1L

为了实现EL-Expressions中的simliar访问可能性,我这样做了: (如果有一个编码神 - 他希望可以原谅我: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();
    }
}

最后,访问同一Long的EL-Expression变为:#{PERMISSION.PAGE.SEE} - Java和EL-Access的相等性。我知道这不符合任何惯例,但它完全正常。

答案 10 :(得分:2)

@Bozho已经提供了一个很好的答案

  

您通常将这些常量放在servlet上下文中的Configuration对象(具有getter和setter)中,并使用$ {applicationScope.config.url}

访问它们。

然而,我觉得需要一个例子,这样可以带来更多的清晰度并节省一些人的时间

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

答案 11 :(得分:0)

有一种解决方法并不完全符合您的要求,但让您以非常小的方式触摸Scriptlet几乎一样。您可以使用scriptlet将值放入JSTL变量中,并在页面的后面使用干净的JSTL代码。

<%@ 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>