จะเรียกวิธีการแบบคงที่ใน JSP / EL ได้อย่างไร?


88

ฉันเพิ่งเริ่มใช้ JSP ฉันลองเชื่อมต่อ MySQL กับเพจ JSP ของฉันแล้วมันก็ใช้ได้ดี แต่นี่คือสิ่งที่ฉันต้องทำ ฉันมีแอตทริบิวต์ของตารางที่เรียกว่า "balance" ดึงข้อมูลและใช้เพื่อคำนวณค่าใหม่ที่เรียกว่า "จำนวนเงิน" (ฉันไม่ได้พิมพ์ "ยอดคงเหลือ")

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

ดูเหมือนว่าจะไม่สามารถแทรก scriptlets ภายในแท็ก JSTL ได้

คำตอบ:


133

คุณไม่สามารถเรียกใช้วิธีการคงที่โดยตรงใน EL EL จะเรียกใช้วิธีการอินสแตนซ์เท่านั้น

ในกรณีที่คุณพยายามใช้สคริปต์เล็ตที่ล้มเหลวคุณไม่สามารถผสมสคริปต์เล็ตและ EL ได้ ใช้อย่างใดอย่างหนึ่ง ตั้งแต่scriptletsกำลังท้อแท้ในช่วงทศวรรษที่คุณควรติดกับโซลูชัน 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 จะเกิดอะไรขึ้นถ้า 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>จะพิมพ์ผลของการแสดงออกเพื่อการส่งออก


ดีกว่านี้อีก! สำหรับคนอื่นคุณสามารถระบุสตริงในวิธีการแบบคงที่โดยการเพิ่ม \ "the_string_argument \" (แทนส่วน row.balance) นี่เป็นกรณีที่วิธีของคุณยกเว้นสตริงเท่านั้น ;) ไชโย!
despot

3
คุณสามารถส่งผ่านสตริงในเครื่องหมายคำพูดเดียวเช่น'the_string_argument'- ไม่จำเป็นต้องเต้นหนี
dma_k

เจ๋งดีที่ได้ผลสำหรับฉันในฤดูใบไม้ผลิ ... ฉันอยากรู้ว่ามันเป็นไปได้ไหมที่จะทำ 2 คลาส ... เพียงแค่ต้องนำหน้า clas ด้วย 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"/>

จากนั้นเรียกใช้ฟังก์ชันที่คุณต้องการโดยใช้ Expression Language:

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

นี่เป็นประโยชน์สำหรับฉัน เยี่ยมมาก !!
Abu Bakar Siddik

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" ในชื่อคลาส
Uluk Biy

2
@UlukBiy Settings.reset()เป็นวิธีการเรียกแบบคงที่ Lukas เสนอการสร้าง ManagedBean ที่มีลักษณะคล้ายกระดาษห่อหุ้มด้วยวิธีการแบบไม่คงที่สำหรับแต่ละวิธีแบบคงที่ซึ่งใคร ๆ ก็ต้องการเรียกจาก EL เป็นวิธีแก้ปัญหาที่ถูกต้อง
Vsevolod Golovanov

3

EL 2.2 มีกลไกการสร้างวิธีการโทร เพิ่มเติมที่นี่: เว็บไซต์ oracle แต่ไม่สามารถเข้าถึงวิธีการคงที่ แม้ว่าคุณจะสามารถเรียกมันผ่านการอ้างอิงวัตถุ แต่ฉันใช้วิธีแก้ปัญหาอื่นที่อธิบายไว้ในบทความนี้: การเรียกใช้วิธีการคงที่จาก EL


1
ฉันอยากรู้ว่า EL 2.2 เพิ่มการสนับสนุนในตัวสำหรับการเรียกวิธีการแบบคงที่ การแก้ปัญหาขึ้นอยู่กับการใส่ bean ลงในบริบทการร้องขอและ (น่าเกลียด) การจำลองแผนที่ + พารามิเตอร์ที่จำเป็นจะถูกส่งผ่านระหว่างการอ้างอิง ภาระเพิ่มเติมของแนวทางนี้คือต้องมีบริบทขอการนวด (เช่นใน<web-app> → <filter>)
dma_k

2

หากคุณใช้ struts2 คุณสามารถใช้

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

จากนั้นอ้างอิง "myVar" ในแอตทริบิวต์แท็ก html หรือ html เป็น ${myVar}


1
สตรัทไม่ใช่ JSP อย่างที่ผู้ถามบอก
bogdan.mustiata

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) ได้
Robert Kornmesser

สวัสดีโรเบิร์ตขอโทษคุณหมายความว่าอย่างไรจริงๆฉันใช้รหัสนั้นมานานแล้วและฉันแน่ใจว่ามันใช้ได้ ความผิดพลาดของฉันอยู่ที่ไหน
ฮวน

ฉันไม่พบข้อมูลจำเพาะของแอคชูออล แต่อย่างที่ 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.
Robert Kornmesser

ใช่คุณไม่สามารถใช้อาร์กิวเมนต์ตัวแปรบน 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>

ในโซลูชันนี้เรากำลังกำหนดค่า (ผ่านแท็กหลัก) ให้กับตัวแปรจากนั้นเราจะดึงค่าของตัวแปรนั้นมาใช้ใน scriplet


0

ใน Struts2 หรือ Webwork2 คุณสามารถใช้สิ่งนี้:

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

จากนั้นอ้างอิง#tourLanguageใน jsp ของคุณ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.