Как вызвать статический метод в JSP / EL?

88

Я новичок в JSP. Я попытался подключить MySQL и свои страницы JSP, и он отлично работает. Но вот что мне нужно было сделать. У меня есть атрибут таблицы под названием «баланс». Получите его и используйте для вычисления нового значения, называемого «сумма». (Я не печатаю «баланс»).

 <c:forEach var="row" items="${rs.rows}">
        ID: ${row.id}<br/>
        Passwd: ${row.passwd}<br/>
        Amount: <%=Calculate.getAmount(${row.balance})%>
 </c:forEach>

Кажется, невозможно вставить скриптлеты в теги JSTL.

Джон
источник

Ответы:

133

Вы не можете вызывать статические методы непосредственно в EL. EL будет вызывать только методы экземпляра.

Что касается неудачной попытки скриптлета , вы не можете смешивать скриптлеты и EL. Используйте то или другое. Поскольку скриптлеты не приветствуются более десяти лет, вам следует придерживаться решения только для EL.

У вас есть в основном 2 варианта (при условии, что оба balanceи Calculate#getAmount()есть double).

  1. Просто оберните его в метод экземпляра.

    public double getAmount() {
        return Calculate.getAmount(balance);
    }
    

    И используйте вместо этого:

    Amount: ${row.amount}
    

  2. Или объявите Calculate#getAmount()как функцию EL. Сначала создайте /WEB-INF/functions.tldфайл:

    <?xml version="1.0" encoding="UTF-8" ?>
    <taglib 
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
        version="2.1">
    
        <display-name>Custom Functions</display-name>    
        <tlib-version>1.0</tlib-version>
        <uri>http://example.com/functions</uri>
    
        <function>
            <name>calculateAmount</name>
            <function-class>com.example.Calculate</function-class>
            <function-signature>double getAmount(double)</function-signature>
        </function>
    </taglib>
    

    И используйте это следующим образом:

    <%@taglib uri="http://example.com/functions" prefix="f" %>
    ...
    Amount: ${f:calculateAmount(row.balance)}">
    
BalusC
источник
@BalusC Что делать, если у моего jsp есть (вычисленное) какое-то значение, и я хотел бы отправить его как параметр ??
Шрирам
7
@Sriram: Во-первых, вы уверены, что не путаете JSP с HTML / JS? То, как вы задаете вопрос, указывает на то, что вы, кажется, думаете, что JSP работает в веб-браузере, хотя это совершенно неверно. JSP - производитель кода HTML / CSS / JS. Вот и все. Это должно дать вам повод задуматься над вашим вопросом и подходом.
BalusC
то, что я искал :)
aliopi
@PhilipRego: код в ответе основан только на рассматриваемом коде.
BalusC
61

Другой подход - использовать Spring SpEL:

<%@taglib prefix="s" uri="http://www.springframework.org/tags" %>

<s:eval expression="T(org.company.Calculate).getAmount(row.balance)" var="rowBalance" />
Amount: ${rowBalance}

Если вы пропустите опцию, var="rowBalance"тогда <s:eval>будет напечатан результат выражения для вывода.

dma_k
источник
это даже лучше! для других вы можете предоставить строку в статическом методе, добавив \ "the_string_argument \" (вместо части row.balance). Это только в том случае, если ваш метод исключает строки. ;) Ура!
деспот
3
Вы можете передавать строки в одинарных кавычках, например 'the_string_argument'- не нужно танцевать с экранированием.
dma_k 08
Круто, это сработало для меня весной ... Мне было любопытно, можно ли сделать 2 класса ... просто нужно добавить к классу префикс T (), я полагаю ... Это сработало для того, что я делал: < s: eval expression = "T (org.jsoup.Jsoup) .clean (orig_text, T (org.jsoup.safety.Whitelist) .none ())" var = "text_stripped_html" /> эквивалент: String text_stripped_html = Jsoup. чистый (orig_text, Whitelist.none ());
armyofda12mnkeys
@msangel: Посмотрите другие ответы в этой теме.
dma_k
5

Если ваш класс Java:

package com.test.ejb.util;

public class CommonUtilFunc {

    public static String getStatusDesc(String status){

        if(status.equals("A")){
            return "Active";
        }else if(status.equals("I")){
            return "Inactive";
        }else{
            return "Unknown";
        }
    }
}

Затем вы можете вызвать статический метод getStatusDesc, как показано ниже на странице JSP.

Используйте JSTL useBean, чтобы получить класс вверху страницы JSP:

<jsp:useBean id="cmnUtilFunc" class="com.test.ejb.util.CommonUtilFunc"/>

Затем вызовите функцию там, где вам нужно, используя язык выражений:

<table>
    <td>${cmnUtilFunc.getStatusDesc('A')}</td>
</table>
Сахан Марасингхе
источник
Это полезно для меня. Большой!!
Абу Бакар Сиддик
4

Bean, подобный StaticInterface, также может использоваться

<h:commandButton value="reset settings" action="#{staticinterface.resetSettings}"/>

и фасоль

package com.example.common;

import com.example.common.Settings;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;

@ManagedBean(name = "staticinterface")
@ViewScoped
public class StaticInterface {

    public StaticInterface() {
    }

    public void resetSettings() {
        Settings.reset();
    }
}
Лукас
источник
Я не вижу в коде никаких статических ключевых слов, кроме «Static» в имени класса.
Улук Бий
2
@UlukBiy, Settings.reset()это вызов статического метода. Лукас предлагает создать ManagedBean, похожий на оболочку, с нестатическим методом для каждого статического метода, который нужно вызывать из EL. Это верное решение.
Всеволод Голованов
3

EL 2.2 имеет встроенный механизм вызова методов. Подробнее здесь: сайт оракула . Но у него нет доступа к статическим методам. Хотя вы все равно можете вызвать его через ссылку на объект. Но я использую другое решение, описанное в этой статье: Вызов статического метода из EL

мсангел
источник
1
Я был бы обеспокоен тем, что EL 2.2 действительно добавляет встроенную поддержку для вызова статического метода. Решения основаны на помещении bean-компонента в контексты запроса и (уродливой) эмуляции карты + необходимые параметры передаются во время разыменования. Дополнительное бремя этого подхода состоит в том, что нужно массировать контекст запроса (например, in <web-app> → <filter>).
dma_k
2

Если вы используете struts2, вы можете использовать

<s:var name='myVar' value="%{@package.prefix.MyClass#myMethod('param')}"/>

а затем укажите "myVar" в атрибуте тега html или html как ${myVar}

dhblah
источник
1
Struts - это не JSP, как сказал спрашивающий.
bogdan.mustiata 06
2

На основе ответа @Lukas вы можете использовать этот bean-компонент и вызвать метод путем отражения:

@ManagedBean (name = "staticCaller")
@ApplicationScoped
public class StaticCaller {
private static final Logger LOGGER = Logger.getLogger(StaticCaller.class);
/**
 * @param clazz
 * @param method
 * @return
 */
@SuppressWarnings("unchecked")
public <E> E call(String clazz, String method, Object... objs){
    final ClassLoader loader = Thread.currentThread().getContextClassLoader();
    final List<Class<?>> clasesparamList = new ArrayList<Class<?>>();
    final List<Object> objectParamList = new ArrayList<Object>();
    if (objs != null && objs.length > 0){
        for (final Object obj : objs){
            clasesparamList.add(obj.getClass());
            objectParamList.add(obj);
        }
    }
    try {           
        final Class<?> clase = loader.loadClass(clazz);
        final Method met = clase.getMethod(method, clasesparamList.toArray(new Class<?>[clasesparamList.size()]));
            return (E) met.invoke(null, objectParamList.toArray());
        } catch (ClassNotFoundException e) {
            LOGGER.error(e.getMessage(), e);
        } catch (InvocationTargetException e) {
            LOGGER.error(e.getMessage(), e);
        } catch (IllegalAccessException e) {
            LOGGER.error(e.getMessage(), e);
        } catch (IllegalArgumentException e) {
            LOGGER.error(e.getMessage(), e);
        } catch (NoSuchMethodException e) {
            LOGGER.error(e.getMessage(), e);
        } catch (SecurityException e) {
            LOGGER.error(e.getMessage(), e);
        }
        return null;
    }
}

xhtml в командную кнопку, например:

<p:commandButton action="#{staticCaller.call('org.company.Calculate', 'getAmount', row.balance)}" process="@this"/>
Хуан
источник
В выражениях метода EL (2.2) нельзя использовать переменные аргументы.
Роберт Корнмессер,
Привет, Роберт, извините, что именно вы имеете в виду, я использовал этот код в течение долгого времени, и я уверен, что он работает. Где моя ошибка?
Хуан,
Я не нахожу спецификации actall, но, как упоминает BalusC здесь stackoverflow.com/questions/15560508/…, это причина SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (http-localhost/127.0.0.1:8080-5) java.lang.IllegalArgumentException: wrong number of arguments.
Роберт Корнмессер,
Да, вы не можете использовать переменные аргументы на EL. Но вы можете использовать этот метод от EL. Его можно использовать для передачи массива в качестве последнего аргумента. В этом случае это не обязательно, потому что в качестве последнего аргумента передается только один объект.
Хуан,
1
<c:forEach var="row" items="${rs.rows}">
        ID: ${row.id}<br/>
        Passwd: ${row.passwd}<br/>
<c:set var="balance" value="${row.balance}"/>
        Amount: <%=Calculate.getAmount(pageContext.getAttribute("balance").toString())%>
 </c:forEach>

В этом решении мы присваиваем значение (через основной тег) переменной, а затем получаем значение этой переменной в скрипте.

ясень9
источник
0

В Struts2 или Webwork2 вы можете использовать это:

<s:set name="tourLanguage" value="@foo.bar.TourLanguage@getTour(#name)"/>

Затем #tourLanguageукажите в своем jsp

sendon1982
источник