如何在EL中引用常量?

发布于 2024-12-05 17:53:50 字数 183 浏览 0 评论 0原文

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

我有一个接口 Addresses ,其中包含一个名为 URL 的常量。我知道我可以通过以下方式使用 scriplet 引用它: <%=Addresses.URL%>,但是如何使用 EL 来执行此操作?

How do you reference an constants with EL on a JSP page?

I have an interface Addresses with a constant named URL. I know I can reference it with a scriplet by going: <%=Addresses.URL%>, but how do I do this using EL?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

冷月断魂刀 2024-12-12 17:53:50

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 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 中。在 EL 中,可以通过 ${map.key}${map['key.with.dots']} 以通常的 Javabean 方式访问映射值。

  2. 使用非标准标签库的(maven2存储库此处):

    <%@ taglib uri="http://jakarta.apache.org/taglibs/unstandard-1.0" prefix="un" %>
    >
    

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

  3. 使用Javaranch的CCC 本文

    <%@ taglib uri="http://bibeault.org/tld/ccc" prefix="ccc" %>;
    
    

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

  4. 如果您使用的是 JSF2,则可以使用 OmniFaces的代码>。

    
    >
    

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

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

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

EL 3.0 or newer

If you're already on Java EE 7 / EL 3.0, then the @page import will also import class constants in EL scope.

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

This will under the covers be imported via ImportHandler#importClass() and be available as ${YourConstants.FOO}.

Note that all java.lang.* classes are already implicitly imported and available like so ${Boolean.TRUE} and ${Integer.MAX_VALUE}. This only requires a more recent Java EE 7 container server as early versions had bugs in this. E.g. GlassFish 4.0 and Tomcat 8.0.0-1x fails, but GlassFish 4.1+ and Tomcat 8.0.2x+ works. And you need to make absolutely sure that your web.xml is declared conform the latest servlet version supported by the server. Thus with a web.xml which is declared conform Servlet 2.5 or older, none of the Servlet 3.0+ features will work.

Also note that this facility is only available in JSP and not in Facelets. In case of JSF+Facelets, your best bet is using OmniFaces <o:importConstants> as below:

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

Or adding an EL context listener which calls ImportHandler#importClass() as below:

@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 or older

This is not possible in EL 2.2 and older. There are several alternatives:

  1. Put them in a Map<String, Object> which you put in the application scope. In EL, map values are accessible the usual Javabean way by ${map.key} or ${map['key.with.dots']}.

  2. Use <un:useConstants> of the 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" />
    

    This way they are accessible the usual Javabean way by ${constants.FOO}.

  3. Use Javaranch's CCC <ccc:constantsMap> as desribed somewhere at the bottom of this article.

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

    This way they are accessible the usual Javabean way by ${constants.FOO} as well.

  4. If you're using JSF2, then you could use <o:importConstants> of OmniFaces.

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

    This way they are accessible the usual Javabean way by #{YourConstants.FOO} as well.

  5. Create a wrapper class which returns them through Javabean-style getter methods.

  6. Create a custom EL resolver which first scans the presence of a constant and if absent, then delegate to the default resolver, otherwise returns the constant value instead.

野侃 2024-12-12 17:53:50

以下内容通常不适用于 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"/>

The following does not apply to EL in general, but instead to SpEL (Spring EL) only (tested with 3.2.2.RELEASE on Tomcat 7).
I think it is worth mentioning it here in case someone searches for JSP and EL (but uses JSP with Spring).

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<spring:eval var="constant" expression="T(com.example.Constants).CONSTANT"/>
话少情深 2024-12-12 17:53:50

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

You usually place these kinds of constants in a Configuration object (which has getters and setters) in the servlet context, and access them with ${applicationScope.config.url}

瀟灑尐姊 2024-12-12 17:53:50

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

You can't. It follows the Java Bean convention. So you must have a getter for it.

梦里泪两行 2024-12-12 17:53:50

我在一开始就在 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 中定义常量时,问题也会出现。

I'm defining a constant in my jsp right at the beginning:

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

I include the core taglib in my JSP:

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

Then, I make the constant available to EL by following statement:

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

Now, I can use it later. Here an example, where the value is just written as HTML comment for debugging purposes:

<!-- ${URI} -->

With your constant class, you can just import your class and assign the constants to local variables. I know that my answer is a sort of quick hack, but the question also bumps up when one wants to define constants directly in the JSP.

阳光①夏 2024-12-12 17:53:50

我实现如下:

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) {
    }
}

添加监听器到

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

jsp 中的 web.xml 访问

${Constants.PAGE_SIZE}

I implemented like:

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

Next step put instance of this class into servlerContext

public class ApplicationInitializer implements ServletContextListener {


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

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

add listener to web.xml

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

access in jsp

${Constants.PAGE_SIZE}
阳光下的泡沫是彩色的 2024-12-12 17:53:50

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

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

我使用 lombok 生成 getter 和 setter,这样就很好了。您的 EL 如下所示:

${bean.manager_role}

完整代码位于 https://rogerkeays .com/access-java-static-methods-and-constants-from-el

Static properties aren't accessible in EL. The workaround I use is to create a non-static variable which assigns itself to the static value.

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

I use lombok to generate the getter and setter so that's pretty well it. Your EL looks like this:

${bean.manager_role}

Full code at https://rogerkeays.com/access-java-static-methods-and-constants-from-el

断肠人 2024-12-12 17:53:50

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

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

:你不必编写吸气剂!

Yes, you can. You need a custom tag (if you can't find it somewhere else). I've done this:

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

and the tag is called:

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

All public static final variables will be put into a Map indexed by their Java name, so if

public static final int MY_FIFTEEN = 15;

then the tag will wrap this in an Integer and you can reference it in a JSP:

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

and you don't have to write getters!

江湖彼岸 2024-12-12 17:53:50

你可以。按照以下方式尝试

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

在 TomCat 7 和 java6 上测试

You can. Try in follow way

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

Tested on TomCat 7 and java6

你不是我要的菜∠ 2024-12-12 17:53:50

即使知道它有点晚了,甚至知道这是一个小黑客 - 我使用以下解决方案来达到预期的结果。如果您是 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 中使用 < code>PERMISSION.PAGE.SEE 检索值 1L

为了从 EL 表达式中实现类似的访问可能性,我这样做了:
(如果有编码大神 - 希望他会原谅我 :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 表达式变为: #{PERMISSION.PAGE.SEE}< /code> - Java 和 EL-Access 相等。我知道这不符合任何惯例,但它工作得很好。

Even knowing its a little late, and even knowing this is a little hack - i used the following solution to achieve the desired result. If you are a lover of Java-Naming-Conventions, my advice is to stop reading here...

Having a class like this, defining Constants, grouped by empty classes to create kind of a hierarchy:

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

can be used from within java as PERMISSION.PAGE.SEE to retrieve the value 1L

To achieve a simliar access-possibility from within EL-Expressions, I did this:
(If there is a coding-god - he hopefully might forgive me :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();
    }
}

finally, the EL-Expression to access the very same Long becomes: #{PERMISSION.PAGE.SEE} - equality for Java and EL-Access. I know this is out of any convention, but it works perfectly fine.

不离久伴 2024-12-12 17:53:50

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

@Bozho already provided a great answer

You usually place these kinds of constants in a Configuration object (which has getters and setters) in the servlet context, and access them with ${applicationScope.config.url}

However, I feel an example is needed so it brings a bit more clarity and spare someone's time

@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);
    }
}
无所的.畏惧 2024-12-12 17:53:50

有一种解决方法并不完全是您想要的,但可以让您以非常简单的方式通过触摸 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>

There is a workaround that is not exactly what you want, but lets you active almost the same with touching scriptlets in a quite minimal way. You can use scriptlet to put value into a JSTL variable and use clean JSTL code later in the 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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文