Як ви посилаєтесь на константи з EL на сторінці JSP?
У мене є інтерфейс Addresses
з постійною назвою URL
. Я знаю, що можу посилатися на це зі скриптом, перейшовши: <%=Addresses.URL%>
але як це зробити за допомогою EL?
Як ви посилаєтесь на константи з EL на сторінці JSP?
У мене є інтерфейс Addresses
з постійною назвою URL
. Я знаю, що можу посилатися на це зі скриптом, перейшовши: <%=Addresses.URL%>
але як це зробити за допомогою EL?
Відповіді:
Якщо ви вже користуєтеся 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 і старше. Є кілька альтернатив:
Помістіть їх у розміщеному 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" />
Таким чином, вони доступні звичайним яванським способом ${constants.FOO}
.
Використовуйте CCC Javaranch так, <ccc:constantsMap>
як описано десь у нижній частині цієї статті .
<%@ taglib uri="http://bibeault.org/tld/ccc" prefix="ccc" %>
<ccc:constantsMap className="com.example.YourConstants" var="constants" />
Таким чином, вони також доступні звичайним яванським способом ${constants.FOO}
.
Якщо ви використовуєте JSF2, то ви могли б використовувати <o:importConstants>
в OmniFaces .
<html ... xmlns:o="http://omnifaces.org/ui">
<o:importConstants type="com.example.YourConstants" />
Таким чином, вони також доступні звичайним яванським способом #{YourConstants.FOO}
.
Створіть клас обгортки, який повертає їх методами геттера в стилі Javabean.
Створіть користувальницьку роздільну здатність EL, яка спочатку сканує наявність константи, а якщо вона відсутня, то делегуйте до роздільної здатності за замовчуванням, інакше натомість повертає постійне значення.
unstandard-taglib
Проект jakarta ще живий? чи є якась альтернатива?
Далі не стосується 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}
url
властивістю String, назвіть його Configuration
, інстанціюйте його та встановіть url
все, що вам подобається. Після цього встановіть цей Configuration
об’єкт в ServletContext
. Робіть щось на кшталт servletContext.setAttribute("config", config)
,. І ось ти йдеш.
ServletContext
? Чи просто ви можете чіткіше класифікувати константи? наприклад: applicationScope.config.url
проти applicationScope.url
.
Ви не можете. Він дотримується конвенції Java Bean. Отже, ви повинні мати для цього геттер.
Статичні властивості недоступні в 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
Я реалізував:
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}
Я визначаю константу в своєму jsp прямо на початку:
<%final String URI = "http://www.example.com/";%>
Я включаю основний таліг в свій JSP:
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
Тоді я роблю константу доступною для EL за допомогою наступного твердження:
<c:set var="URI" value="<%=URI%>"></c:set>
Тепер я можу використовувати його пізніше. Ось приклад, де значення просто пишеться як коментар HTML для цілей налагодження:
<!-- ${URI} -->
Зі своїм постійним класом ви можете просто імпортувати свій клас і призначати константи локальним змінним. Я знаю, що моя відповідь є своєрідним швидким злому, але питання також стикається, коли хочеться визначати константи безпосередньо в JSP.
<%=URI%>
: P
<%=URI%>
не працював, але ця техніка так і зробила.
Так, ти можеш. Вам потрібен спеціальний тег (якщо ви не можете його знайти десь ще). Я зробив це:
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-імена, моя порада перестати читати тут ...
Маючи такий клас, визначаючи константи, згруповані по порожніх класах для створення свого роду ієрархії:
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, я зробив це: (Якщо є бог кодування - він, сподіваюся, може пробачити мене: 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. Я знаю, що це поза будь-якою умовою, але це прекрасно працює.
@Bozho вже дав чудову відповідь
Зазвичай ви розміщуєте ці види констант в об'єкті конфігурації (у якому є геттери та сетери) в контексті сервлетів і отримуєте доступ до них за допомогою $ {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>