Como chamar um método estático em JSP / EL?

87

Sou novo no JSP. Tentei conectar o MySQL e minhas páginas JSP e funcionou bem. Mas aqui está o que eu precisava fazer. Eu tenho um atributo de tabela chamado "equilíbrio". Recupere-o e use-o para calcular um novo valor denominado "montante". (Não estou imprimindo "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 não é possível inserir scriptlets em tags JSTL.

John
fonte

Respostas:

131

Você não pode invocar métodos estáticos diretamente no EL. EL só invocará métodos de instância.

Quanto à tentativa de scriptlet com falha , você não pode misturar scriptlets e EL. Use um ou outro. Como os scriptlets são desencorajados ao longo de uma década, você deve se ater a uma solução somente EL.

Você tem basicamente 2 opções (assumindo que balancee Calculate#getAmount()são double).

  1. Basta envolvê-lo em um método de instância.

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

    E use-o em seu lugar:

    Amount: ${row.amount}

  2. Ou declare Calculate#getAmount()como uma função EL. Primeiro crie um /WEB-INF/functions.tldarquivo:

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

    E use-o da seguinte maneira:

    <%@taglib uri="http://example.com/functions" prefix="f" %>
    ...
    Amount: ${f:calculateAmount(row.balance)}">
BalusC
fonte
@BalusC E se meu jsp tiver (calculado) algum valor e eu quiser enviar isso como parâmetro ??
Sriram de
7
@Sriram: Em primeiro lugar, você tem certeza de que não está confundindo JSP com HTML / JS? A maneira como você colocou a pergunta indica que você parece pensar que o JSP é executado no navegador da web, embora isso seja completamente falso. JSP é um produtor de código HTML / CSS / JS. Isso é tudo. Isso deve dar a você algo para pensar sobre sua pergunta e abordagem.
BalusC de
o que eu estava procurando :)
aliopi
@PhilipRego: o código em resposta é baseado apenas no código em questão.
BalusC
61

Outra abordagem é usar 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}

Se você pular o opcional var="rowBalance", <s:eval>o resultado da expressão será impresso para a saída.

dma_k
fonte
isso é ainda melhor! para outros, você pode fornecer uma string no método estático adicionando \ "the_string_argument \" (ao invés da parte row.balance). Isso ocorre apenas se o seu método exclui strings. ;) Felicidades!
déspota
3
Você pode passar strings em aspas simples, por exemplo 'the_string_argument'- não há necessidade de dançar com o escape.
dma_k
Legal, funcionou para mim na primavera ... Eu estava curioso se era possível fazer 2 aulas ... só preciso prefixar as classes com um T () presumo ... Funcionou para o que eu estava fazendo: < 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. limpar (orig_text, Whitelist.none ());
armyofda12mnkeys
@msangel: Verifique outras respostas neste tópico.
dma_k
5

Se sua classe Java for:

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

Então você pode chamar o método estático 'getStatusDesc' como abaixo na página JSP.

Use JSTL useBean para obter a classe no topo da página JSP:

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

Em seguida, chame a função onde você solicitou usando Expression Language:

<table>
    <td>${cmnUtilFunc.getStatusDesc('A')}</td>
</table>
Sahan Marasinghe
fonte
Isso é útil para mim. Ótimo!!
Abu Bakar Siddik
4

Bean como StaticInterface também pode ser usado

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

e feijão

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
fonte
Não consigo ver nenhuma palavra-chave estática no código, exceto "Estático" no nome da classe.
Uluk Biy
2
@UlukBiy, Settings.reset()é uma chamada de método estático. Lukas propõe a criação de um ManagedBean tipo wrapper com um método não estático para cada método estático, que se deseja chamar de EL. É uma solução válida.
Vsevolod Golovanov
3

EL 2.2 tem mecanismo embutido de métodos de chamada. Mais aqui: site da oracle . Mas não tem acesso a métodos estáticos. Embora você ainda possa chamá-lo por meio de referência de objeto. Mas eu uso outra solução, descrita neste artigo: Chamando um método estático de EL

msangel
fonte
1
Eu diria que EL 2.2 realmente adiciona um suporte embutido para chamar um método estático. As soluções são baseadas em colocar um bean em contextos de solicitação e emulações (feias) de um mapa + parâmetros necessários são passados ​​durante a desreferenciação. O fardo adicional desta abordagem é que é necessário massagear o contexto de solicitação (por exemplo, em <web-app> → <filter>).
dma_k
2

Se você estiver usando struts2, você pode usar

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

e, em seguida, referenciar 'myVar' no atributo html ou tag html como ${myVar}

dhblah
fonte
1
Struts não é JSP, como disse o autor da pergunta.
bogdan.mustiata
2

Com base na resposta de @Lukas, você pode usar esse bean e o método de chamada por reflexão:

@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, em um botão de comando, por exemplo:

<p:commandButton action="#{staticCaller.call('org.company.Calculate', 'getAmount', row.balance)}" process="@this"/>
Juan
fonte
Não é possível usar argumentos variáveis ​​em expressões de método EL (2.2).
Robert Kornmesser
Olá, Robert, desculpe o que você quer dizer exatamente, eu uso esse código há muito tempo e tenho certeza que funciona. Onde está meu erro?
Juan
Não encontrei a especificação real, mas como BalusC menciona aqui stackoverflow.com/questions/15560508/… este é o motivo SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (http-localhost/127.0.0.1:8080-5) java.lang.IllegalArgumentException: wrong number of arguments.
Robert Kornmesser
Sim, você não pode usar argumentos variáveis ​​em EL. Mas você pode usar esse método de EL. Ele pode ser usado passando um array como último argumento. Nesse caso, não é necessário porque há apenas um objeto passado 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>

Nesta solução, atribuímos valor (por meio da tag principal) a uma variável e, em seguida, buscamos o valor dessa variável no scriplet.

ash9
fonte
0

No Struts2 ou Webwork2, você pode usar isto:

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

Então referência #tourLanguageem seu jsp

sendon1982
fonte