Jak wywołać metodę statyczną w JSP / EL?

88

Jestem nowy w JSP. Próbowałem połączyć MySQL i moje strony JSP i działa dobrze. Ale oto, co musiałem zrobić. Mam atrybut tabeli o nazwie „balance”. Pobierz go i użyj do obliczenia nowej wartości o nazwie „kwota”. (Nie drukuję „Balance”).

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

Wygląda na to, że nie można wstawić skryptletów w znaczniki JSTL.

Jan
źródło

Odpowiedzi:

133

Nie można wywoływać metod statycznych bezpośrednio w EL. EL będzie wywoływać tylko metody instancji.

Jeśli chodzi o nieudaną próbę użycia skryptletu , nie możesz mieszać skryptletów i EL. Użyj jednego lub drugiego. Ponieważ od ponad dekady zniechęca się do używania skryptów , powinieneś trzymać się rozwiązania tylko dla EL.

Masz w zasadzie 2 opcje (zakładając, że obie są balancei Calculate#getAmount()double).

  1. Po prostu zawiń go w metodę instancji.

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

    I zamiast tego użyj:

    Amount: ${row.amount}
    

  2. Lub zadeklaruj Calculate#getAmount()jako funkcję EL. Najpierw utwórz /WEB-INF/functions.tldplik:

    <?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>
    

    I użyj go w następujący sposób:

    <%@taglib uri="http://example.com/functions" prefix="f" %>
    ...
    Amount: ${f:calculateAmount(row.balance)}">
    
BalusC
źródło
@BalusC Co jeśli mój jsp ma (obliczył) jakąś wartość i chciałbym to wysłać jako parametr?
Sriram
7
@Sriram: Po pierwsze, czy jesteś pewien, że nie mylisz JSP z HTML / JS? Sposób, w jaki postawiłeś pytanie, wskazuje, że wydaje Ci się, że wydaje Ci się, iż JSP działa w przeglądarce internetowej, podczas gdy jest to całkowicie nieprawdziwe. JSP jest producentem kodu HTML / CSS / JS. To wszystko. To powinno dać ci do myślenia o swoim pytaniu i podejściu.
BalusC
czego szukałem :)
aliopi
@PhilipRego: kod w odpowiedzi jest oparty na pytanym kodzie.
BalusC
61

Innym podejściem jest użycie 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}

Jeśli pominąć opcjonalnie var="rowBalance"następnie <s:eval>drukuje wynik wyrażenia do wyjścia.

dma_k
źródło
to jest jeszcze lepsze! dla innych możesz podać ciąg w metodzie statycznej, dodając \ "the_string_argument \" (zamiast części row.balance). Dzieje się tak tylko wtedy, gdy twoja metoda nie używa ciągów. ;) Twoje zdrowie!
despota
3
Ciągi można podawać w pojedynczych cudzysłowach, np. 'the_string_argument'- nie trzeba tańczyć z ucieczką.
dma_k
Fajnie, to zadziałało na wiosnę ... Byłem ciekawy, czy można zrobić 2 zajęcia ... po prostu muszę poprzedzić klasy literą T (), zakładam ... To zadziałało w przypadku tego, co robiłem: < s: eval expression = "T (org.jsoup.Jsoup) .clean (orig_text, T (org.jsoup.safety.Whitelist) .none ())" var = "text_stripped_html" /> odpowiednik: String text_stripped_html = Jsoup. czysty (orig_text, Whitelist.none ());
armyofda12mnkeys
@msangel: Sprawdź inne odpowiedzi w tym temacie.
dma_k
5

Jeśli Twoja klasa Java to:

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";
        }
    }
}

Następnie możesz wywołać metodę statyczną „getStatusDesc”, jak poniżej na stronie JSP.

Użyj useBean JSTL, aby uzyskać klasę u góry strony JSP:

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

Następnie wywołaj funkcję, w której potrzebujesz, używając języka wyrażeń:

<table>
    <td>${cmnUtilFunc.getStatusDesc('A')}</td>
</table>
Sahan Marasinghe
źródło
To jest dla mnie pomocne. Świetny!!
Abu Bakar Siddik
4

Można również użyć bean jak StaticInterface

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

i fasola

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();
    }
}
Lukas
źródło
Nie widzę w kodzie żadnego statycznego słowa kluczowego z wyjątkiem „Static” w nazwie klasy.
Uluk Biy
2
@UlukBiy, Settings.reset()to statyczne wywołanie metody. Lukas proponuje utworzenie ManagedBean przypominającego opakowanie z metodą niestatyczną dla każdej metody statycznej, którą chce się wywołać z EL. To prawidłowe rozwiązanie.
Vsevolod Golovanov
3

EL 2.2 ma wbudowany mechanizm wywoływania metod. Więcej tutaj: witryna oracle . Ale nie ma dostępu do metod statycznych. Chociaż możesz nadal wywoływać to poprzez odniesienie do obiektu. Ale używam innego rozwiązania, opisanego w tym artykule: Wywołanie metody statycznej z EL

msangel
źródło
1
Szkoda, że ​​EL 2.2 naprawdę dodaje wbudowaną obsługę wywoływania metody statycznej. Rozwiązanie polega na umieszczeniu beana w kontekstach żądań i (brzydkiej) emulacji mapy + niezbędne parametry są przekazywane podczas dereferencji. Dodatkowym obciążeniem tego podejścia jest konieczność masowania kontekstu żądania (np. W <web-app> → <filter>).
dma_k
2

Jeśli używasz struts2, możesz użyć

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

a następnie odwołaj się do „myVar” w atrybucie tagu html lub html jako ${myVar}

dhblah
źródło
1
Struts to nie JSP, jak powiedział pytający.
bogdan.mustiata
2

Na podstawie odpowiedzi @Lukas możesz użyć tej fasoli i metody wywołania przez refleksję:

@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, do przycisku poleceń, na przykład:

<p:commandButton action="#{staticCaller.call('org.company.Calculate', 'getAmount', row.balance)}" process="@this"/>
Juan
źródło
Nie jest możliwe użycie argumentów zmiennych w wyrażeniach metody EL (2.2).
Robert Kornmesser
Cześć Robert, przepraszam, co dokładnie masz na myśli, używam tego kodu przez długi czas i jestem pewien, że działa. Gdzie jest mój błąd?
Juan
Nie znajduję aktualnej specyfikacji, ale jak BalusC wspomina tutaj stackoverflow.com/questions/15560508/… to jest powód SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (http-localhost/127.0.0.1:8080-5) java.lang.IllegalArgumentException: wrong number of arguments.
Robert Kornmesser
Tak, nie możesz używać zmiennych argumentów w EL. Ale możesz użyć tej metody z EL. Można go użyć przekazując tablicę jako ostatni argument. W tym przypadku nie jest to konieczne, ponieważ jako ostatni argument przekazano tylko jeden obiekt.
Juan
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>

W tym rozwiązaniu przypisujemy wartość (poprzez tag core) do zmiennej, a następnie pobieramy wartość tej zmiennej w scriplecie.

popiół9
źródło
0

W Struts2 lub Webwork2 możesz użyć tego:

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

Następnie #tourLanguageodwołaj się do pliku jsp

sendon1982
źródło