Làm thế nào để gọi một phương thức tĩnh trong JSP / EL?


88

Tôi mới tham gia JSP. Tôi đã thử kết nối MySQL và các trang JSP của mình và nó hoạt động tốt. Nhưng đây là những gì tôi cần làm. Tôi có một thuộc tính bảng được gọi là "số dư". Lấy nó và sử dụng nó để tính toán một giá trị mới được gọi là "số tiền". (Tôi không in "số dư").

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

Có vẻ như không thể chèn các script trong thẻ JSTL.

Câu trả lời:


133

Bạn không thể gọi phương thức tĩnh trực tiếp trong EL. EL sẽ chỉ gọi các phương thức thể hiện.

Đối với thất bại của bạn scriptlet nỗ lực, bạn không thể trộn scriptlets và EL. Sử dụng cái này hay cái kia. Vì kịch bản không được khuyến khích trong hơn một thập kỷ, bạn nên sử dụng giải pháp chỉ dành cho EL.

Về cơ bản bạn có 2 lựa chọn (giả sử là cả hai balanceCalculate#getAmount()đều có double).

  1. Chỉ cần bọc nó trong một phương thức thể hiện.

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

    Và sử dụng nó thay thế:

    Amount: ${row.amount}
    

  2. Hoặc, khai báo Calculate#getAmount()dưới dạng một hàm EL. Đầu tiên hãy tạo một /WEB-INF/functions.tldtệp:

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

    Và sử dụng nó như sau:

    <%@taglib uri="http://example.com/functions" prefix="f" %>
    ...
    Amount: ${f:calculateAmount(row.balance)}">
    

@BalusC Điều gì sẽ xảy ra nếu jsp của tôi có (được tính toán) một số giá trị và tôi muốn gửi giá trị đó dưới dạng tham số ??
Sriram 14/11/12

7
@Sriram: Trước hết, bạn có chắc rằng bạn không nhầm lẫn giữa JSP với HTML / JS không? Cách bạn đặt câu hỏi cho thấy rằng dường như bạn nghĩ rằng JSP chạy trong trình duyệt web trong khi điều này hoàn toàn không đúng sự thật. JSP là một trình tạo mã HTML / CSS / JS. Đó là tất cả. Điều đó sẽ cung cấp cho bạn điều gì đó để suy nghĩ về câu hỏi và cách tiếp cận của bạn.
BalusC

những gì tôi đang tìm kiếm :)
aliopi

@PhilipRego: mã trong câu trả lời chỉ dựa trên mã được đề cập.
BalusC

61

Một cách tiếp cận khác là sử dụng 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}

Nếu bạn bỏ qua tùy chọn var="rowBalance"thì <s:eval>sẽ in kết quả của biểu thức để xuất.


điều này thậm chí còn tốt hơn! đối với những người khác, bạn có thể cung cấp một chuỗi trong phương thức tĩnh bằng cách thêm \ "the_string_argument \" (thay vì phần row.balance). Điều này chỉ xảy ra nếu phương thức của bạn loại trừ các chuỗi. ;) Chúc mừng!
despot

3
Bạn có thể chuyển các chuỗi trong dấu ngoặc đơn, ví dụ 'the_string_argument'- không cần phải nhảy với thoát.
dma_k

Tuyệt vời, điều đó đã làm việc cho tôi vào mùa xuân ... Tôi tò mò liệu có thể thực hiện 2 lớp ... chỉ cần đặt trước các clas bằng một T () tôi giả sử ... Điều này hiệu quả với những gì tôi đang làm: < s: eval expression = "T (org.jsoup.Jsoup) .clean (orig_text, T (org.jsoup.safety.Whitelist) .none ())" var = "text_stripped_html" /> tương đương với: String text_stripped_html = Jsoup. sạch (orig_text, Whitelist.none ());
armyofda12mnkeys

@msangel: Kiểm tra các câu trả lời khác trong chủ đề này.
dma_k

5

Nếu lớp Java của bạn là:

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

Sau đó, bạn có thể gọi phương thức tĩnh 'getStatusDesc' như bên dưới trong trang JSP.

Sử dụng JSTL useBean để nhận lớp ở đầu trang JSP:

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

Sau đó gọi hàm khi bạn yêu cầu bằng Ngôn ngữ Biểu thức:

<table>
    <td>${cmnUtilFunc.getStatusDesc('A')}</td>
</table>

Điều này rất hữu ích cho tôi. Tuyệt quá!!
Abu Bakar Siddik

4

Bean như StaticInterface cũng có thể được sử dụng

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

và đậu

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

Tôi không thể thấy bất kỳ từ khóa tĩnh nào trong mã ngoại trừ "Tĩnh" trong tên lớp.
Uluk Biy

2
@UlukBiy, Settings.reset()là một cuộc gọi phương thức tĩnh. Lukas đề xuất tạo một ManagedBean giống như trình bao bọc với một phương thức không tĩnh cho mỗi phương thức tĩnh, mà một phương thức muốn gọi từ EL. Đó là một giải pháp hợp lệ.
Vsevolod Golovanov

3

EL 2.2 có cơ chế gọi phương thức inbuild. Thêm ở đây: trang oracle . Nhưng nó không có quyền truy cập vào các phương thức tĩnh. Mặc dù bạn vẫn có thể gọi nó thông qua tham chiếu đối tượng. Nhưng tôi sử dụng một giải pháp khác, được mô tả trong bài viết này: Gọi một phương pháp tĩnh từ EL


1
Tôi sẽ tin rằng EL 2.2 thực sự bổ sung một hỗ trợ tích hợp để gọi một phương thức tĩnh. Các giải pháp dựa trên việc đặt một bean vào các ngữ cảnh yêu cầu và mô phỏng (xấu xí) một bản đồ + các thông số cần thiết được chuyển trong quá trình tham khảo. Gánh nặng bổ sung của cách tiếp cận này là người ta cần phải điều chỉnh bối cảnh yêu cầu (ví dụ: trong <web-app> → <filter>).
dma_k

2

Nếu bạn đang sử dụng struts2, bạn có thể sử dụng

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

và sau đó tham chiếu 'myVar' trong thuộc tính thẻ html hoặc html dưới dạng ${myVar}


1
Struts không phải là JSP, như người hỏi đã nói.
bogdan.mustiata

2

Dựa trên câu trả lời @Lukas, bạn có thể sử dụng phương thức bean và cuộc gọi đó bằng cách phản ánh:

@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, vào một nút lệnh, ví dụ:

<p:commandButton action="#{staticCaller.call('org.company.Calculate', 'getAmount', row.balance)}" process="@this"/>

Không thể sử dụng đối số biến trong biểu thức phương thức EL (2.2).
Robert Kornmesser 13/10/16

Xin chào Robert, xin lỗi bạn nói chính xác là gì, tôi đã sử dụng mã đó trong một thời gian dài và tôi chắc chắn rằng nó hoạt động. Sai lầm của tôi ở đâu?
Juan

Tôi không tìm thấy thông số kỹ thuật của actuall, nhưng như BalusC đề cập ở đây stackoverflow.com/questions/15560508/… thì đây là lý do của SEVERE [javax.enterprise.resource.webcontainer.jsf.context] (http-localhost/127.0.0.1:8080-5) java.lang.IllegalArgumentException: wrong number of arguments.
Robert Kornmesser,

Có, bạn không thể sử dụng các đối số biến trên EL. Nhưng bạn có thể sử dụng phương pháp đó từ EL. Nó có thể được sử dụng để truyền một mảng làm đối số cuối cùng. Trong trường hợp này, nó không cần thiết vì chỉ có một đối tượng được truyền làm đối số cuối cùng.
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>

Trong giải pháp này, chúng tôi đang gán giá trị (Thông qua thẻ lõi) cho một biến và sau đó chúng tôi đang tìm nạp giá trị của biến đó trong scriplet.


0

Trong Struts2 hoặc Webwork2, bạn có thể sử dụng cái này:

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

Sau đó, tham khảo #tourLanguagetrong jsp của bạn

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.