Як посилатися на константи в EL?


106

Як ви посилаєтесь на константи з EL на сторінці JSP?

У мене є інтерфейс Addressesз постійною назвою URL. Я знаю, що можу посилатися на це зі скриптом, перейшовши: <%=Addresses.URL%>але як це зробити за допомогою EL?

Відповіді:


156

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 і старше. Є кілька альтернатив:

  1. Помістіть їх у розміщеному Map<String, Object>вами додатку. У EL значення значень карт доступні звичайним способом Javabean шляхом ${map.key}або ${map['key.with.dots']}.

  2. Використання <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}.

  3. Використовуйте CCC Javaranch так, <ccc:constantsMap>як описано десь у нижній частині цієї статті .

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

    Таким чином, вони також доступні звичайним яванським способом ${constants.FOO}.

  4. Якщо ви використовуєте JSF2, то ви могли б використовувати <o:importConstants>в OmniFaces .

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

    Таким чином, вони також доступні звичайним яванським способом #{YourConstants.FOO}.

  5. Створіть клас обгортки, який повертає їх методами геттера в стилі Javabean.

  6. Створіть користувальницьку роздільну здатність EL, яка спочатку сканує наявність константи, а якщо вона відсутня, то делегуйте до роздільної здатності за замовчуванням, інакше натомість повертає постійне значення.


4
Я знайшов це питання, оскільки у мене виникли ті ж проблеми при спробі використовувати статичне поле Список із тегом form: options. Мені вдалося змусити його працювати, додавши нестатичний getter, який повертає статичний список. Це трохи дивовижно, але ей, це розвиток JSP для вас!
spaaarky21

1
Чи є у вас приклад, як налаштувати це для JSF, якщо бобами керують до весни? Thx заздалегідь.
Лоджер

2
@Lodger: Я не весну.
BalusC

2
unstandard-taglibПроект jakarta ще живий? чи є якась альтернатива?
davioooh

1
Чи є спосіб використовувати цю техніку для переліків?
Ніклас Петро

11

Далі не стосується 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"/>

9

Зазвичай ви розміщуєте ці види констант в Configurationоб'єкті (в якому є геттери та сетери) в контексті сервлетів і отримуєте доступ до них за допомогою${applicationScope.config.url}


Тут трохи новачка, якщо мова йде про jsp's - чи могли б ви пояснити це повніше?
тау-нейтрино

1
@ tau-нейтрино: Насправді все просто. Створіть клас із urlвластивістю String, назвіть його Configuration, інстанціюйте його та встановіть urlвсе, що вам подобається. Після цього встановіть цей Configurationоб’єкт в ServletContext. Робіть щось на кшталт servletContext.setAttribute("config", config),. І ось ти йдеш.
Адель Ансарі

Яка різниця між запропонованим рішенням та простим додаванням константи як атрибуту ServletContext? Чи просто ви можете чіткіше класифікувати константи? наприклад: applicationScope.config.urlпроти applicationScope.url.
вони

7

Ви не можете. Він дотримується конвенції Java Bean. Отже, ви повинні мати для цього геттер.


5

Статичні властивості недоступні в 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


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}

4

Я визначаю константу в своєму 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.


1
хаха, чому б не використовувати Scriptlets безпосередньо, якщо саме так ви ініціалізуєте змінні EL?
Навін

Три лінії на вершині безладдя, а потім очистіть EL по всій решті JSP ^^.
коппор

1
@koppoor я думаю, що так. Я просто збираюся використовувати <%=URI%>: P
Navin

1
У мене було місце, де прямий <%=URI%>не працював, але ця техніка так і зробила.
englebart

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, так, якщо

public static final int MY_FIFTEEN = 15;

тоді тег загорне це в цілий ряд, і ви можете посилатися на нього в JSP:

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

і вам не потрібно писати гетерів!


3

Ти можеш. Спробуйте наступним чином

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

Тестували на TomCat 7 та java6


3
Це схоже на SpEL, а не на EL. Я помиляюся? Також, чи буде це працювати в старшому Tomcat5.5?
Пітрий

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, я зробив це: (Якщо є бог кодування - він, сподіваюся, може пробачити мене: 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. Я знаю, що це поза будь-якою умовою, але це прекрасно працює.


2

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

0

Існує рішення, яке не є саме тим, що ви хочете, але дозволяє вам майже так само активно торкатися сценаріїв. Ви можете використовувати скриплет для введення значення в змінну 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>

1
Я не бачу, чому це було знято. Це та сама картина, що і варіант №3: stackoverflow.com/a/16692821/274677
Маркус Юній Брут
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.