Как ссылаться на константы в EL?
Как вы ссылаетесь на константы с EL на странице JSP?
У меня есть интерфейс Addresses
с константой по имени URL
, Я знаю, что могу сослаться на это с помощью скрипта: <%=Addresses.URL%>
, но как мне сделать это с помощью EL?
12 ответов
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
объявляется соответствующей последней версии сервлета, поддерживаемой сервером. Таким образом, с web.xml
который объявлен в соответствии с Servlet 2.5 или старше, ни одна из функций Servlet 3.0+ не будет работать.
Также обратите внимание, что это средство доступно только в JSP, а не в Facelets. В случае с JSF+Facelets вам лучше всего использовать OmniFaces <o:importConstants>
как показано ниже:
<o:importConstants type="com.example.YourConstants" />
Или добавив EL слушатель контекста, который вызывает ImportHandler#importClass()
как показано ниже:
@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 и старше. Есть несколько альтернатив:
Поместите их в
Map<String, Object>
который вы положили в область применения. В EL значения карты доступны обычным способом Javabean${map.key}
или же${map['key.with.dots']}
,использование
<un:useConstants>
Нестандартного taglib ( репозиторий maven2 здесь):<%@ taglib uri="http://jakarta.apache.org/taglibs/unstandard-1.0" prefix="un" %> <un:useConstants className="com.example.YourConstants" var="constants" />
Таким образом, они доступны обычным Javabean способом
${constants.FOO}
,Используйте Javaranch's CCC
<ccc:constantsMap>
как описано где-то внизу этой статьи.<%@ taglib uri="http://bibeault.org/tld/ccc" prefix="ccc" %> <ccc:constantsMap className="com.example.YourConstants" var="constants" />
Таким образом, они доступны обычным Javabean способом
${constants.FOO}
также.Если вы используете JSF2, то вы можете использовать
<o:importConstants>
OmniFaces.<html ... xmlns:o="http://omnifaces.org/ui"> <o:importConstants type="com.example.YourConstants" />
Таким образом, они доступны обычным Javabean способом
#{YourConstants.FOO}
также.Создайте класс-оболочку, который возвращает их через методы получения в стиле Javabean.
Создайте пользовательский распознаватель EL, который сначала сканирует наличие постоянной, а если ее нет, затем делегирует преобразователю по умолчанию, в противном случае вместо него возвращается значение константы.
Следующее не относится к EL в целом, но вместо этого только к SpEL (Spring EL) (протестировано с 3.2.2.RELEASE на Tomcat 7). Я думаю, что стоит упомянуть об этом здесь, если кто-то ищет JSP и EL (но использует JSP с Spring).
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<spring:eval var="constant" expression="T(com.example.Constants).CONSTANT"/>
Вы обычно помещаете эти виды констант в Configuration
объект (который имеет геттеры и сеттеры) в контексте сервлета, и доступ к ним с помощью ${applicationScope.config.url}
Ты не можешь Это соответствует соглашению Java Bean. Таким образом, вы должны иметь добытчик для этого.
Я реализовал как:
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}
Статические свойства не доступны в EL. Обходной путь, который я использую, заключается в создании нестатической переменной, которая присваивает себя статическому значению.
public final static String MANAGER_ROLE = 'manager';
public String manager_role = MANAGER_ROLE;
Я использую lombok для генерации геттера и сеттера, так что это довольно хорошо. Ваш EL выглядит так:
${bean.manager_role}
Полный код на http://www.ninthavenue.com.au/java-static-constants-in-jsp-and-jsf-el
Я определяю константу в моем JSP в самом начале:
<%final String URI = "http://www.example.com/";%>
Я включаю основной taglib в мой JSP:
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
Затем я делаю константу доступной для EL следующим утверждением:
<c:set var="URI" value="<%=URI%>"></c:set>
Теперь я могу использовать это позже. Вот пример, где значение просто записывается как HTML-комментарий для целей отладки:
<!-- ${URI} -->
С вашим константным классом вы можете просто импортировать свой класс и назначить константы локальным переменным. Я знаю, что мой ответ - это своего рода быстрый взлом, но вопрос также возникает, когда кто-то хочет определить константы непосредственно в JSP.
Да, ты можешь. Вам нужен собственный тег (если вы не можете найти его где-то еще). Я сделал это:
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-имени, так что если
public static final int MY_FIFTEEN = 15;
тогда тег обернет это в целое число, и вы можете сослаться на него в JSP:
<c:if test="${consts['MY_FIFTEEN'] eq 15}">
и вам не нужно писать геттеры!
Вы можете. Попробуйте следующим образом
#{T(com.example.Addresses).URL}
Протестировано на TomCat 7 и java6
Даже зная, что немного поздно, и даже зная, что это немного взломать - я использовал следующее решение для достижения желаемого результата. Если вы любитель Java-Naming-Conventions, мой совет, прекратите читать здесь...
Имея такой класс, определяя константы, сгруппированные по пустым классам для создания иерархии:
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-выражений, я сделал это: (Если есть бог кодирования - он, возможно, простит меня: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();
}
}
наконец, EL-Expression для доступа к тому же Long
будет выглядеть так: #{PERMISSION.PAGE.SEE}
- равенство для Java и EL-Access. Я знаю, что это вне какого-либо соглашения, но это прекрасно работает.
@ Божо уже дал отличный ответ
Вы обычно помещаете эти виды констант в объект конфигурации (который имеет методы получения и установки) в контексте сервлета и обращаетесь к ним с помощью ${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);
}
}
Существует обходной путь, который не совсем то, что вам нужно, но позволяет вам практически одинаково активировать прикосновения к скриптлетам в минимальной степени. Вы можете использовать скриптлет для помещения значения в переменную 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>