¿Cómo llamar a un método estático en JSP / EL?

88

Soy nuevo en JSP. Intenté conectar MySQL y mis páginas JSP y funciona bien. Pero esto es lo que necesitaba hacer. Tengo un atributo de tabla llamado "equilibrio". Recupéralo y úsalo para calcular un nuevo valor llamado "monto". (No estoy imprimiendo "saldo").

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

Parece que no es posible insertar scriptlets dentro de las etiquetas JSTL.

Juan
fuente

Respuestas:

133

No puede invocar métodos estáticos directamente en EL. EL solo invocará métodos de instancia.

En cuanto a su intento fallido de scriptlet , no puede mezclar scriptlets y EL. Utilice el uno o el otro. Dado que los scriptlets se desaconsejan durante una década, debe ceñirse a una solución exclusiva para EL.

Tiene básicamente 2 opciones (asumiendo que ambas balancey Calculate#getAmount()son double).

  1. Simplemente envuélvalo en un método de instancia.

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

    Y utilícelo en su lugar:

    Amount: ${row.amount}
    

  2. O declare Calculate#getAmount()como una función EL. Primero crea un /WEB-INF/functions.tldarchivo:

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

    Y utilícelo de la siguiente manera:

    <%@taglib uri="http://example.com/functions" prefix="f" %>
    ...
    Amount: ${f:calculateAmount(row.balance)}">
    
BalusC
fuente
@BalusC ¿Qué pasa si mi jsp tiene (calculado) algún valor y me gustaría enviarlo como parámetro?
Sriram
7
@Sriram: En primer lugar, ¿estás seguro de que no estás confundiendo JSP con HTML / JS? La forma en que formula la pregunta indica que parece pensar que JSP se ejecuta en el navegador web, mientras que esto es completamente falso. JSP es un productor de código HTML / CSS / JS. Eso es todo. Eso debería darle algo en que pensar sobre su pregunta y enfoque.
BalusC
lo que estaba buscando :)
aliopi
@PhilipRego: el código en respuesta se basa solo en el código en cuestión.
BalusC
61

Otro enfoque es utilizar 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}

Si omite opcional var="rowBalance", <s:eval>se imprimirá el resultado de la expresión en la salida.

dma_k
fuente
¡esto es aún mejor! para otros, puede proporcionar una cadena en el método estático agregando \ "the_string_argument \" (en lugar de la parte row.balance). Esto es solo si su método exceptúa cadenas. ;) ¡Salud!
déspota
3
Puede pasar cadenas entre comillas simples, por ejemplo 'the_string_argument', no es necesario bailar con el escape.
dma_k
Genial, eso funcionó para mí en Spring ... Tenía curiosidad por saber si era posible hacer 2 clases ... solo necesito anteponer la clase con una T () supongo ... Esto funcionó para lo que estaba haciendo: < s: eval expression = "T (org.jsoup.Jsoup) .clean (orig_text, T (org.jsoup.safety.Whitelist) .none ())" var = "text_stripped_html" /> equivalente a: String text_stripped_html = Jsoup. limpio (texto_orig, Lista blanca.none ());
armyofda12mnkeys
@msangel: Verifique otras respuestas en este tema.
dma_k
5

Si su clase de Java es:

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

Luego puede llamar al método estático 'getStatusDesc' como se muestra a continuación en la página JSP.

Use JSTL useBean para obtener la clase en la parte superior de la página JSP:

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

Luego llame a la función donde lo requirió usando Expression Language:

<table>
    <td>${cmnUtilFunc.getStatusDesc('A')}</td>
</table>
Sahan Marasinghe
fuente
Esto me ayuda. ¡¡Excelente!!
Abu Bakar Siddik
4

Bean como StaticInterface también se puede utilizar

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

y frijol

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
fuente
No puedo ver ninguna palabra clave estática en el código excepto "Static" en el nombre de la clase.
Uluk Biy
2
@UlukBiy, el Settings.reset() es una llamada a un método estático. Lukas propone crear un ManagedBean similar a un contenedor con un método no estático para cada método estático, al que se quiera llamar desde EL. Es una solucion valida.
Vsevolod Golovanov
3

EL 2.2 tiene un mecanismo incorporado de métodos de llamada. Más aquí: sitio de Oracle . Pero no tiene acceso a métodos estáticos. Aunque todavía puede llamarlo a través de la referencia de objeto. Pero uso otra solución, descrita en este artículo: Llamar a un método estático desde EL

msangel
fuente
1
Yo diría que EL 2.2 realmente agrega un soporte integrado para llamar a un método estático. La solución se basa en poner un bean en contextos de solicitud y emulaciones (feas) se pasan un mapa + parámetros necesarios durante la desreferenciación. La carga adicional de este enfoque es que es necesario masajear el contexto de la solicitud (por ejemplo, en <web-app> → <filter>).
dma_k
2

Si está usando struts2, podría usar

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

y luego haga referencia a 'myVar' en el atributo de etiqueta html o html como ${myVar}

dhblah
fuente
1
Struts no es JSP, como dijo el autor de la pregunta.
bogdan.mustiata
2

Según la respuesta de @Lukas, puede usar ese bean y llamar al método por reflexión:

@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, en un botón de comando, por ejemplo:

<p:commandButton action="#{staticCaller.call('org.company.Calculate', 'getAmount', row.balance)}" process="@this"/>
Juan
fuente
No es posible utilizar argumentos variables en expresiones del método EL (2.2).
Robert Kornmesser
Hola Robert, lo siento, ¿qué quieres decir exactamente? He usado ese código durante mucho tiempo y estoy seguro de que funciona. Donde esta mi error
Juan
No encuentro la especificación actual, pero como BalusC menciona aquí stackoverflow.com/questions/15560508/… esta es la razón SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (http-localhost/127.0.0.1:8080-5) java.lang.IllegalArgumentException: wrong number of arguments.
Robert Kornmesser
Sí, no puede usar argumentos variables en EL. Pero puedes usar ese método de EL. Se puede usar pasando una matriz como último argumento. En este caso no es necesario porque solo se pasa un objeto como último argumento.
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>

En esta solución, estamos asignando valor (a través de la etiqueta principal) a una variable y luego obtenemos el valor de esa variable en scriplet.

ceniza9
fuente
0

En Struts2 o Webwork2, puede usar esto:

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

Luego haga referencia #tourLanguageen su jsp

sendon1982
fuente