如何在JSP页面上引用EL常量?
我有一个名为Addresses
的常量接口URL
。我知道我可以用一个scriplet来引用它:<%=Addresses.URL%>
,但我怎么用EL做这个呢?
答案 0 :(得分:150)
如果您已经使用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及更早版本中可能不。有几种选择:
将它们放入您放入应用程序范围的Map<String, Object>
中。在EL中,可以通过${map.key}
或${map['key.with.dots']}
通常的Javabean方式访问地图值。
使用<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方式访问它们。
在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方式访问。
如果您使用的是JSF2,则可以使用<o:importConstants>
的OmniFaces。
<html ... xmlns:o="http://omnifaces.org/ui">
<o:importConstants type="com.example.YourConstants" />
这样他们也可以通过#{YourConstants.FOO}
通常的Javabean方式访问。
创建一个包装类,通过Javabean样式的getter方法返回它们。
创建自定义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>