<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    一個(gè)帶有Ajax功能的JSF組件的完整詳細(xì)開(kāi)發(fā)過(guò)程

        文章有點(diǎn)長(zhǎng),寫(xiě)得比較詳細(xì),有興趣與耐心開(kāi)發(fā)JSF組件的就往下看吧,下面將詳細(xì)介紹一個(gè)標(biāo)準(zhǔn)JSF組件的制作過(guò)程,并且后面將使用QFaces將它升級(jí)為Ajax方式的組件(如果要升級(jí)為Ajax組件,請(qǐng)先安裝QFaces增強(qiáng)框架).如果你發(fā)現(xiàn)有任何問(wèn)題或錯(cuò)漏,請(qǐng)給予批評(píng)指正,相關(guān)的完整代碼在QFaces的Demo示例中,可以自行下載查看:

        QFaces相關(guān)完整示例下載

        現(xiàn)在先來(lái)看一下一個(gè)JSF標(biāo)準(zhǔn)組件所需要用到的一些文件:

    1.UIComponent ― 組件的主類,用于組件渲染,狀態(tài)的保存及一些行為的處理等.

    2.UIComponentTag - 組件的jsp標(biāo)簽處理類,主要進(jìn)行值綁定及方法綁定等.

    3.tld - 標(biāo)簽庫(kù)描述符文件,主要用于注冊(cè)組件的可用屬性等.

    4.faces-config.xml - 配置文件,主要用于注冊(cè)你的組件.

    注意的是,我們這里所介紹的環(huán)境是JSF1.2JSP視圖的組件, 如果你使用了facelets視圖技術(shù),則可以省去UIComponentTagtld文件,制作組件的方法基本相同,但注冊(cè)及方法綁定稍有不同.

    現(xiàn)在我們來(lái)一步一步創(chuàng)建一個(gè)組件吧,暫且把這個(gè)組件的名字取為:Hello

    步驟1.創(chuàng)建UIComponent – HtmlHello.java

     

    public class HtmlHello extends UIComponentBase implements Ajax{

        @Override
        
    public String getFamily() {
            
    return null;
        }

        
    public void ajaxInvokeOnPost(Map<String, String> params, FacesContext fc) {
            
    throw new UnsupportedOperationException("Not supported yet.");
        }

        
    public void ajaxInvokeOnGet(Map<String, String> params, FacesContext fc) {
            
    // 后面我們將實(shí)現(xiàn)這個(gè)方法
        }

    }

        為了簡(jiǎn)單起見(jiàn),我們繼承了比較基礎(chǔ)的UIComponentBase 同時(shí)實(shí)現(xiàn)QFaces中的Ajax接口,Ajax接口需要實(shí)現(xiàn)兩個(gè)方法:ajaxInvokeOnPost ajaxInvokeOnPost 分別處理postget請(qǐng)求,可以選擇實(shí)現(xiàn),后面我們將實(shí)現(xiàn)ajaxInvokeOnGet這個(gè)方法,因?yàn)檫@對(duì)性能很好,如果你只需要一個(gè)標(biāo)準(zhǔn)JSF組件,可以不實(shí)現(xiàn)這個(gè)接口.在這里我們需要先進(jìn)行一些其它方面的工作:渲染組件

    為了渲染組件,我們需要覆蓋encodeBegin方法:

    public class HtmlHello extends UIComponentBase implements Ajax{

        @Override
        
    public String getFamily() {
            
    return null;
        }

        
    public void ajaxInvokeOnPost(Map<String, String> params, FacesContext fc) {
            
    throw new UnsupportedOperationException("Not supported yet.");
        }

        
    public void ajaxInvokeOnGet(Map<String, String> params, FacesContext fc) {
            
    // 我們將實(shí)現(xiàn)這個(gè)方法
        }

        @Override
        
    public void encodeBegin(FacesContext fc) throws IOException {
            String clientId 
    = this.getClientId(fc); // 獲得組件的客戶端ID
            ResponseWriter rw = fc.getResponseWriter();
            rw.startElement(
    "input"this);
            rw.writeAttribute(
    "id", clientId, null);
            rw.writeAttribute(
    "name", clientId, null);
            rw.writeAttribute(
    "type""text"null);
            rw.endElement(
    "input"
    );
        }


    }

    你可以看到我們實(shí)現(xiàn)的encodeBegin方法,實(shí)際上只是在客戶端渲染一個(gè)input而已,如果渲染正常,應(yīng)該在html代碼中輸出像這樣的東西:

    <input type=”text” id=”…” name=”…” />

    接著我們先確保這個(gè)組件能在頁(yè)面中正常渲染并顯示,所以我們先注冊(cè)一下這個(gè)組件,并看一下效果,后面再實(shí)現(xiàn)組件的Ajax功能.

    步驟2.創(chuàng)建UIComponentTag – HtmlHelloTag.java

     


    public class HtmlHelloTag extends UIComponentELTag{

        @Override
        
    public String getComponentType() {
            
    return "demo.component.HtmlHello";
        }

        @Override
        
    public String getRendererType() {
            
    return null;
        }

    }


    這一步中我們只是創(chuàng)建了一個(gè)java類并擴(kuò)展UIComponentELTag, 覆蓋了getComponentType, 這個(gè)方法會(huì)告訴JSP使用哪一個(gè)主類來(lái)處理頁(yè)面標(biāo)簽.類似于一個(gè)橋梁作用,后面會(huì)看到這是如何聯(lián)系到我們的主類HtmlHello.java的.

    getRendererType方法只返回null, 因?yàn)槲覀兊慕M件主類HtmlHello會(huì)自行渲染.所以不需要其它渲染類.

    好了,HtmlHelloTag.java就這樣簡(jiǎn)單,我們暫時(shí)不需要其他屬性(idrendered屬性默認(rèn)已經(jīng)有了,我們只要在tld文件中登記一下就可以),接著我們來(lái)將這個(gè)HtmlHelloTag注冊(cè)到tld文件中.


    步驟3.創(chuàng)建TLD標(biāo)簽庫(kù)描述符文件 – MyComponent.tld


    <?xml version="1.0" encoding="UTF-8"?>
    <taglib xsi:schemaLocation="
    http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
     
    xmlns
    ="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi
    ="http://www.w3.org/2001/XMLSchema-instance" 
    version
    ="2.1">
        
    <description>在這里登記標(biāo)簽庫(kù)的名稱,版本,以及頁(yè)面引用時(shí)指定的uri</description>
        
    <display-name>MyComponents</display-name>
        
    <short-name>mc</short-name>
        
    <tlib-version>1.0</tlib-version>
        
    <uri>http://mycomponents/demo</uri>
        
        
    <tag>
            
    <name>hello</name>
            
    <tag-class>
                demo.component.HtmlHelloTag
            
    </tag-class>
            
    <attribute>
                
    <name>id</name>
            
    </attribute>
            
    <attribute>
                
    <name>rendered</name>
                
    <deferred-value>
                    
    <type>java.lang.Boolean</type>
                
    </deferred-value>
            
    </attribute>
        
    </tag>
    </taglib>

    MyComponent.tld這個(gè)文件的名稱并沒(méi)有什么特殊的或需要約定的規(guī)則,把它直接放在WEB-INF文件夾下就可以了,JSF會(huì)自己去找到它.

    你完全可以直接復(fù)制這個(gè)文件來(lái)進(jìn)行修改,這里指定了組件庫(kù)的名稱,版本,引用時(shí)的uri,需要注意的是uri中指定的http://mycomponents/demo可以自己指定,但要與JSP頁(yè)面引用時(shí)一致如:<%@taglib prefix="mc" uri="http://mycomponents/demo"%>

    另外,你可以在<tag>中看到我們將HtmlHelloTag注冊(cè)到了這個(gè)tld描述文件,<tag-class>中我們指定了標(biāo)簽處理類的完全限定類名,<name>中我們給這個(gè)標(biāo)簽指定了一個(gè)名稱:hello, 后面我們可以這樣使用這個(gè)標(biāo)簽組件:<mc:hello />,同時(shí)我們把idrendered屬性登記了上去,這是兩個(gè)基本屬性,每個(gè)擴(kuò)展自UIComponentELTag的類都會(huì)處理,所以這里登記一下就可以了。

    處理完UIComponentTagtld文件之后,我們只要再一步將自己的Component主類注冊(cè)到faces-config.xml文件中就可以了。

    步驟4.將組件注冊(cè)到faces-config.xml

    <faces-config version="1.2" 
        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-facesconfig_1_2.xsd">

        
    <component>
            
    <component-type>demo.component.HtmlHello</component-type>
            
    <component-class>
                demo.component.HtmlHello
            
    </component-class>
        
    </component>
    </faces-config>

    faces-config.xml文件中,我們注冊(cè)了前面創(chuàng)建的組件HtmlHello. <component-class>中指定了這個(gè)組件的主類的完全限定類名,<component-type>指定了這個(gè)組件的類型,實(shí)際上你可以使用其它自定的component-type,但是這個(gè)名稱必須與HtmlHelloTag.java中的方法:getComponentType所返回的名稱是一致的:

    public String getComponentType() {

            return "demo.component.HtmlHello";

        }

    tmlHelloTag.java就是這樣聯(lián)系到這個(gè)組件的主類的。

    提示:你可以自己新創(chuàng)建一個(gè)faces-config.xml文件或使用JSF自己的faces-config.xml來(lái)注冊(cè)你的新組件,如果另外創(chuàng)建一個(gè)faces-config.xml,那么你需要在web.xml中登記這個(gè)文件的路徑。

    步驟5.先測(cè)試一下這個(gè)組件

    接著,我們先創(chuàng)建一個(gè)jsp頁(yè)面HelloDemo.jsp來(lái)測(cè)試一下新創(chuàng)建的組件,


    然后引入我們自定義的標(biāo)簽庫(kù),uri需要與我們?cè)?/span>tld中定義的相同。

    <%@taglib prefix="mc" uri="http://mycomponents/demo"%>


    這時(shí)當(dāng)我們打入“<m”的時(shí)候jsp已經(jīng)有了新定義組件的一些提示,下面看一下組件是否可以正常顯示,以下是HelloDemo.jsp的代碼:


    <%@page contentType="text/html" pageEncoding="UTF-8"%>
    <%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
    <%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%>
    <%@taglib prefix="mc" uri="http://mycomponents/demo"%>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
       "http://www.w3.org/TR/html4/loose.dtd"
    >

    <f:view>
    <html>
        
    <head>
            
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
            
    <title>Demo</title>
        
    </head>
        
    <body>
            
    <h2>Hello Demo</h2>
            
            
    <mc:hello />
            
            
    <%@ include file="../back.jsp" %>
        
    </body>
    </html>
    </f:view>


    可以看到組件已經(jīng)可以正常的顯示了, 簡(jiǎn)單的顯示了一個(gè)input,雖然確實(shí)非常簡(jiǎn)單,并且?guī)缀鯖](méi)有一點(diǎn)作用。不過(guò)這基本上就是一個(gè)標(biāo)準(zhǔn)JSF組件的創(chuàng)建過(guò)程,知道了原理之后我們就可以擴(kuò)展出更多更高級(jí)的功能了。如果你只需要一個(gè)標(biāo)準(zhǔn)組件,那么到這一步就可以了.

    接下來(lái)我們將使用QFaces給組件增加Ajax的功能,提高用戶體驗(yàn)。

    步驟6Ajax擴(kuò)展 創(chuàng)建javascript文件 HtmlHello.js

        先創(chuàng)建一個(gè)javascript文件:HtmlHello.js 為了方便起見(jiàn),在這里將它創(chuàng)建在了component包中,與組件的主類等放在一起,這也有利于以后將組件打包成jar,方便部署.


    接著開(kāi)始編寫(xiě)這個(gè)js腳本,敲入如下的ajax請(qǐng)求代碼,后面你會(huì)知道組件是如何觸發(fā)這個(gè)腳本的.


    function qfaces_demo_hello(clientId, componentClass) {
        var obj 
    = QFaces.getObj(clientId); // 獲取QFacesObject對(duì)象
        var hello = QFaces.getComponent(clientId); // 獲取組件
        obj.put("componentClass", componentClass); // 這個(gè)參數(shù)是組件get請(qǐng)求必要的
        obj.put("myname", hello.value); // 這個(gè)參數(shù)是我們自己要進(jìn)行傳遞的參數(shù)
        var process = function () { // 定義回調(diào)處理函數(shù)
            alert(obj.request.responseText);
        }
        obj.setProcess(process); 
    // 設(shè)置回調(diào)處理函數(shù)
        obj.get()// 發(fā)送請(qǐng)求(get方式,必須傳遞參數(shù)componentClass)
    }

    一些解釋:

    QFaces是我自定義的一個(gè)javascript類,可以方便處理ajax請(qǐng)求,已經(jīng)簡(jiǎn)化掉了很多幾乎沒(méi)有作用,或經(jīng)常重復(fù)多余的代碼.這個(gè)類是如何引入的,后面會(huì)在組件的渲染中介紹.(你可以直接解開(kāi)QFacesjar文件,從中找到這個(gè)js進(jìn)行一些修改或許對(duì)你有用)

    clientId組件的客戶端id, 查看html源碼,可以看到jsf組件的客戶端id都像這樣 xxx:xxx:xxx

    componentClass 組件的java類的完全限定類名.

    后面在組件的渲染中,我們將傳遞這兩個(gè)值給這個(gè)js函數(shù).下面是QFacesQFacesObject類的解釋:

    1.       QFaces.getObj(clientId):可以獲取一個(gè)處理這次請(qǐng)求的js對(duì)象QFacesObject,為了避免當(dāng)頁(yè)面同時(shí)存在多個(gè)hello組件時(shí)發(fā)生全局的XMLHttpRequest沖突,所以傳遞了組件唯一的clientId, 并且在整個(gè)請(qǐng)求過(guò)程中,你仍然可以通過(guò)clientId在其它方法中獲得這個(gè)QFacesObject,它是全局的,里面包含了一些有用的東西,如XMLHttpRequest對(duì)象,下面是QFacesObject的一些有用的東西:

    2.       put()方法:可以很方便的設(shè)置傳遞參數(shù),經(jīng)過(guò)改造看起來(lái)很像java Map類的put方法.

    3.       setProcess(function):設(shè)置回調(diào)時(shí)的處理函數(shù),在這里我們直接將Ajax帶回來(lái)的數(shù)據(jù)alert出來(lái).

    4.       get() post()方法:這兩個(gè)方法分別表示了get請(qǐng)求與post請(qǐng)求.但是有一些不同,使用get方法必需要傳遞參數(shù)”componentClass”即組件的完全限定類名.而post方法必需要傳遞”clientId”即組件的客戶端id.

    因?yàn)?/span>get方法中框架使用了反射機(jī)制處理請(qǐng)求,所以需要知道是哪一個(gè)組件類發(fā)起的請(qǐng)求,并調(diào)用相應(yīng)的處理方法(ajaxInvokeOnGet),但是Post方法卻是通過(guò)clientId來(lái)查找組件,并調(diào)用相應(yīng)的處理方法(ajaxInvokeOnPost).

    Post方法性能較差,因?yàn)樗麜?huì)傳遞整個(gè)組件樹(shù)的狀態(tài)信息,并進(jìn)行恢復(fù)視圖等處理.在我的多次測(cè)試中,這個(gè)階段幾乎至少要花掉約20毫秒的時(shí)間,如果頁(yè)面視圖足夠復(fù)雜可能花費(fèi)的時(shí)間更多,但是Get方法不需要這個(gè)階段,它不需要跑任何生命周期,就好像你寫(xiě)servletFilter來(lái)處理這個(gè)請(qǐng)求一樣.

    但是在某些時(shí)候post方法非常有用,他可以訪問(wèn)到整個(gè)組件樹(shù)中的所有組件.QFaces.jar包中的validator組件使用的就是這個(gè)方式,它需要訪問(wèn)目標(biāo)組件的value,validator,convert等屬性,

    盡管post方式性能稍差,但是QFaces中還是幫你省下了JSF生命周期中的后面5個(gè)階段.所以性能還是有所保障的.

    5.       QFaces.getComponent(“id”) 獲取頁(yè)面組件,為什么不使用document.getElementById(“id”)? 有時(shí)候你可能會(huì)發(fā)現(xiàn)某些瀏覽器下無(wú)法正常通過(guò)id獲取頁(yè)面組件,所以定義了這個(gè)方法,更好的兼容多瀏覽器.

    步驟7Ajax擴(kuò)展 讓組件UIComponent觸發(fā)js

    現(xiàn)在開(kāi)始升級(jí)一下前面創(chuàng)建的組件主類HtmlHello.java,讓它能觸發(fā)js調(diào)用,并進(jìn)行ajax請(qǐng)求.


    public class HtmlHello extends UIComponentBase implements Ajax{

        @Override
        
    public String getFamily() {
            
    return null;
        }

        
    public void ajaxInvokeOnPost(Map<String, String> params, FacesContext fc) {
            
    throw new UnsupportedOperationException("Not supported yet.");
        }

        
    public void ajaxInvokeOnGet(Map<String, String> params, FacesContext fc) {
            
    // 我們將實(shí)現(xiàn)這個(gè)方法
        }

        @Override
        
    public void encodeBegin(FacesContext fc) throws IOException {
            QFaces.loadRequired(); 
    // 裝載必要的資源如QFaces.js
            QFaces.loadJavascript("demo/component/HtmlHello.js"this); // 裝載自定義的js
            String componentClass = this.getClass().getName(); // 獲取組件的完全限定類名
            String clientId = this.getClientId(fc); // 獲得組件的客戶端ID
            
            // 組織js函數(shù)用于組件的onblur - javascript:qfaces_demo_hello("…", "…");
            StringBuilder onblur = new StringBuilder("javascript:qfaces_demo_hello(");
            onblur.append(
    "'").append(clientId).append("'");
            onblur.append(
    ",'").append(componentClass).append("'");
            onblur.append(
    ")"
    );
            
            ResponseWriter rw 
    = fc.getResponseWriter();
            rw.startElement(
    "input"this);
            rw.writeAttribute(
    "id", clientId, null);
            rw.writeAttribute(
    "name", clientId, null);
            rw.writeAttribute(
    "type""text"null);
            rw.writeAttribute(
    "onblur", onblur, null);
            rw.endElement(
    "input");
        }

    }

    你可以看到升級(jí)的encodeBegin方法在渲染組件之前裝載了QFaces必要的js資源及我們自定義的HtmlHello.js資源(注意資源路徑是"/"而非"."符號(hào)), 并且給組件增加了一個(gè)onblur屬性, 這個(gè)就是調(diào)用我們新定義的js函數(shù)的屬性了:qfaces_demo_hello(clientId,componentClass)

    你可能會(huì)擔(dān)心多個(gè)組件同時(shí)在頁(yè)面的時(shí)候會(huì)導(dǎo)致重復(fù)加載js資源的問(wèn)題,不過(guò)這個(gè)問(wèn)題QFaces已經(jīng)作了處理.

    現(xiàn)在先來(lái)測(cè)試一下組件是否可以正常的觸發(fā)這個(gè)js函數(shù)吧,稍微修改一下:qfaces_demo_hello:


    function qfaces_demo_hello(clientId, componentClass) {
        alert(
    "clientId=" + clientId + "\ncomponentClass=" + componentClass);
    //    var obj = QFaces.getObj(clientId);
    //
        var hello = QFaces.getComponent(clientId);
    //
        obj.put("componentClass", componentClass);
    //
        obj.put("myname", hello.value);
    //
        var process = function () {
    //
            alert(obj.request.responseText);
    //
        }
    //
        obj.setProcess(process);
    //
        obj.get();
    }


    可以看到正常的觸發(fā)了這個(gè)函數(shù),顯示了組件傳遞給jsclientIdcomponentClass

    現(xiàn)在重新修改回正常的js請(qǐng)求,并進(jìn)行下一步Ajax請(qǐng)求的最終應(yīng)答處理:


    function qfaces_demo_hello(clientId, componentClass) {
        
    var obj = QFaces.getObj(clientId);
        
    var hello = QFaces.getComponent(clientId);
        obj.put(
    "componentClass", componentClass);
        obj.put(
    "myname", hello.value);
        
    var process = function () {
            alert(obj.request.responseText);
        }
        obj.setProcess(process);
        obj.get();
    }

    步驟8Ajax擴(kuò)展 讓組件UIComponent響應(yīng)Ajax請(qǐng)求

     

    現(xiàn)在我們開(kāi)始處理Ajax請(qǐng)求的響應(yīng),回到組件主類HtmlHello.java來(lái)實(shí)現(xiàn)最初的方法ajaxInvokeOnGet, 下面是響應(yīng)的方法實(shí)現(xiàn):

    public void ajaxInvokeOnGet(Map<String, String> params, FacesContext fc) {

            String myname = params.get("myname");

            String message = "Hello, welcome to use QFaces! " + myname;

            QFaces.ResponseHTML(fc, message);

        }

    你可以看到這個(gè)方法很簡(jiǎn)單,取回了我們通過(guò)js發(fā)送過(guò)來(lái)的參數(shù)myname的值,并組織新值message,然后使用QFacesResponseHTML方法直接響應(yīng)這個(gè)字符串.當(dāng)然你也可以從FacesContext中獲得response對(duì)象進(jìn)行自定義響應(yīng).現(xiàn)在看一下最終效果截圖:


    在輸入了一些信息之后,焦點(diǎn)離開(kāi)組件,彈出了我們最終想要的效果!這已經(jīng)是一個(gè)完整的帶有Ajax功能的組件了.但它的復(fù)用性并不好,因?yàn)槲覀冇簿幋a了Ajax響應(yīng).接下來(lái)的"進(jìn)一步升級(jí)"會(huì)讓組件支持BackingBean方法綁定.使它可以進(jìn)行重用.如果你有興趣就繼續(xù)往下看.

    3. 進(jìn)一步升級(jí) - 創(chuàng)建一個(gè)可重用的Ajax組件

    現(xiàn)在先簡(jiǎn)單回顧一下上面整個(gè)組件的制作過(guò)程,及處理流程:

    制作過(guò)程

    1.創(chuàng)建組件主類HtmlHello.java ->

    2.創(chuàng)建標(biāo)簽屬性處理類HtmlHelloTag.java ->

    3.創(chuàng)建tld標(biāo)簽描述符定義標(biāo)簽庫(kù),并將HtmlHelloTag.java注冊(cè)到其中 ->

    4.創(chuàng)建faces-config.xml(可以直接使用jsf自帶的),并將組件注冊(cè)到其中. ->

    5.測(cè)試組件可以正常渲染并運(yùn)行 ->

    6.(升級(jí))創(chuàng)建js文件HtmlHello.js ->

    7.(升級(jí))讓組件能裝載js并觸發(fā)jsajax請(qǐng)求 ->

    8.(升級(jí))讓組件響應(yīng)Ajax請(qǐng)求

    處理流程

    1.JSP頁(yè)面發(fā)現(xiàn)組件標(biāo)簽<mc:hello /> ->

    2.JSF根據(jù)tld中定義的TagHtmlHelloTag.java來(lái)設(shè)置相應(yīng)標(biāo)簽屬性的值 ->

    3.HtmlHelloTag.java根據(jù)getComponentType的返回值確定組件的主處理類的類型 ->

    4.HtmlHelloTag.java將相應(yīng)的屬性和值綁定等賦給組件主類 ->

    5.組件主類HtmlHello.java開(kāi)始渲染自己(1.加載QFaces.js, HtmlHello.js 2.渲染一個(gè)input) ->

    6.頁(yè)面逞現(xiàn),input輸入信息并離開(kāi)焦點(diǎn)后觸發(fā)js : qfaces_demo_hello進(jìn)行Ajax請(qǐng)求 ->

    7.QFaces根據(jù)請(qǐng)求的參數(shù)componentClass確定相應(yīng)的處理類HtmlHello.java

    8.QFaces調(diào)用HtmlHello.javaajaxInvokeOnGet進(jìn)行Ajax的響應(yīng).

    現(xiàn)在開(kāi)始升級(jí)方法綁定,為了節(jié)省篇幅,后面的敘述及部驟可能不會(huì)太過(guò)詳細(xì),但代碼仍是完整的.我們將使組件可以綁定一個(gè)這樣的方法:

    java.lang.String showMessage(java.lang.String)

    這個(gè)方法將獲取用戶輸入組件的值,同時(shí)用Ajax返回一些提示或驗(yàn)證信息,使用方法像這樣

    <mc:hello showMessage=”#{DemoBean.showMessage}” />

    1.       升級(jí)MyComponent.tld


    <?xml version="1.0" encoding="UTF-8"?>
    <taglib xsi:schemaLocation="
    http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
     
    xmlns
    ="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi
    ="http://www.w3.org/2001/XMLSchema-instance" 
    version
    ="2.1">
        
    <description>在這里登記標(biāo)簽庫(kù)的名稱,版本,以及頁(yè)面引用時(shí)指定的uri</description>
        
    <display-name>MyComponents</display-name>
        
    <short-name>mc</short-name>
        
    <tlib-version>1.0</tlib-version>
        
    <uri>http://mycomponents/demo</uri>
        
        
    <tag>
            
    <name>hello</name>
            
    <tag-class>
                demo.component.HtmlHelloTag
            
    </tag-class>
            
    <attribute>
                
    <name>id</name>
            
    </attribute>
            
    <attribute>
                
    <name>rendered</name>
                
    <deferred-value>
                    
    <type>java.lang.Boolean</type>
                
    </deferred-value>
            
    </attribute>
            
    <attribute>
                
    <name>showMessage</name>
                
    <deferred-method>
                    
    <method-signature>
                        java.lang.String showMessage(java.lang.String)
                    
    </method-signature>
                
    </deferred-method>
            
    </attribute>

        
    </tag>
    </taglib>

    現(xiàn)在我們?cè)?/span>tld文件中注冊(cè)了一個(gè)新的屬性showMessage,他綁定了一個(gè)這樣的方法:

    java.lang.String showMessage(java.lang.String)

    2.       升級(jí)組件主類HtmlHello.java的渲染


    public class HtmlHello extends UIComponentBase implements Ajax{
        @Override
        
    public String getFamily() {
            
    return null;
        }

        
    public void ajaxInvokeOnPost(Map<String, String> params, FacesContext fc) {
            
    throw new UnsupportedOperationException("Not supported yet.");
        }

        
    public void ajaxInvokeOnGet(Map<String, String> params, FacesContext fc) {
            String myname 
    = params.get("myname");
            String message 
    = "Hello, welcome to use QFaces! " + myname;
            QFaces.ResponseHTML(fc, message);
        }

        @Override
        
    public void encodeBegin(FacesContext fc) throws IOException {
            QFaces.loadRequired();
            QFaces.loadJavascript(
    "demo/component/HtmlHello.js"this);
            String componentClass 
    = this.getClass().getName();
            String clientId 
    = this.getClientId(fc); 
            // 取得方法綁定的表達(dá)式
            String messageExp = (this.showMessage != null ? 
                        
    this.showMessage.getExpressionString() : null
    );
            
            
    // 組織js函數(shù)用于組件的onblur:javascript:qfaces_demo_hello("", "", "");
            StringBuilder onblur = new StringBuilder("javascript:qfaces_demo_hello(");
            onblur.append(
    "'").append(clientId).append("'");
            onblur.append(
    ",'").append(componentClass).append("'");
            onblur.append(
    ",'").append(messageExp).append("'"); // 增加傳遞的參數(shù)
            onblur.append(")");
            
            ResponseWriter rw 
    = fc.getResponseWriter();
            rw.startElement(
    "input"this);
            rw.writeAttribute(
    "id", clientId, null);
            rw.writeAttribute(
    "name", clientId, null);
            rw.writeAttribute(
    "type""text"null);
            rw.writeAttribute(
    "onblur", onblur, null);
            rw.endElement(
    "input");
        }
        
        
    private MethodExpression showMessage;
        
    public void setShowMessage(MethodExpression showMessage) {
            
    this.showMessage =
     showMessage;
        }

    }

    3.       升級(jí) HtmlHelloTag.java


    public class HtmlHelloTag extends UIComponentELTag{

        @Override
        
    public String getComponentType() {
            
    return "demo.component.HtmlHello";
        }

        @Override
        
    public String getRendererType() {
            
    return null;
        }

        @Override
        
    protected void setProperties(UIComponent ui) {
            
    super.setProperties(ui);
            
    if (ui instanceof demo.component.HtmlHello) { // 設(shè)置組件的方法綁定
                ((HtmlHello) ui).setShowMessage(showMessage);
            }
        }


        @Override
        
    public void release() {
            
    super.release();
            
    this.showMessage = null// 釋放資源
        }
        
        private MethodExpression showMessage;

        
    public void setShowMessage(MethodExpression showMessage) {
            
    this.showMessage =
     showMessage;
        }

    }

    4.       升級(jí) HtmlHello.js


    function qfaces_demo_hello(clientId, componentClass, messageExp) {
        
    var obj = QFaces.getObj(clientId);
        
    var hello = QFaces.getComponent(clientId);
        obj.put(
    "componentClass", componentClass);
        obj.put(
    "myname", hello.value);
        obj.put(
    "messageExp", messageExp); // 傳遞方法綁定的表達(dá)式
        var process = function () {
            alert(obj.request.responseText);
        }
        obj.setProcess(process);
        obj.get();
    }

    5.       升級(jí)組件主類的響應(yīng)處理

    現(xiàn)在升級(jí)一下主類的ajaxInvokeOnGet使它能處理方法綁定.

    public void ajaxInvokeOnGet(Map<String, String> params, FacesContext fc) {
            String myname 
    = params.get("myname");
            String messageExp 
    = params.get("messageExp"); // 取回方法綁定的表達(dá)式
            MethodExpression me = QFaces.createMethodExpression(messageExp, 
                    String.
    classnew Class[]{String.class}); // 重建這個(gè)方法綁定
            String result = (String) me.invoke(fc.getELContext(), new Object[]{myname}); // 調(diào)用
            QFaces.ResponseHTML(fc, result); // 輸出響應(yīng)
    }

    6.       新建BackingBean – DemoBean.java

    現(xiàn)在新建一個(gè)backingBean – DemoBean.java 并增加一個(gè)方法進(jìn)行測(cè)試

    public class DemoBean {
        
    public String showMessage(String myname) {
            String message 
    = "你好, 很高興見(jiàn)到你! " + myname;
            
    return message;
        }
    }

    7.       最終測(cè)試


    <%@page contentType="text/html" pageEncoding="UTF-8"%>
    <%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
    <%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%>
    <%@taglib prefix="mc" uri="http://mycomponents/demo"%>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
       "http://www.w3.org/TR/html4/loose.dtd"
    >

    <f:view>
    <html>
        
    <head>
            
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
            
    <title>Demo</title>
        
    </head>
        
    <body>
            
    <h2>Hello Demo</h2>
            
            
    <mc:hello showMessage="#{DemoBean.showMessage}" />
            
            
    <%@ include file="../back.jsp" %>
        
    </body>
    </html>
    </f:view>

    現(xiàn)在輸入信息并onblur之后你可以看到更好的響應(yīng)輸出了,組件支持了方法綁定,重用程度變得更好!

    好了就寫(xiě)到這里吧.更多的值綁定,狀態(tài)保存,validator...等等.還是需要自己更深入的了解JSF,當(dāng)能夠自如的了解并制作組件這后,我相信你應(yīng)該也會(huì)覺(jué)得它確實(shí)很好用的. 實(shí)際上這也并沒(méi)有什么高深的知識(shí),任何復(fù)雜的問(wèn)題都是由日常生活中非常簡(jiǎn)單的道理構(gòu)成的.只要知道了原理,再深入研究,一切都會(huì)變得很簡(jiǎn)單.這與其它行業(yè)不同,比如重工業(yè),你知道了某些原理,沒(méi)有一些資金支持,購(gòu)買(mǎi)硬件設(shè)備供研究的話也是白搭,

    但編程卻不同,幾乎只要一臺(tái)電腦就什么都有可能,呵呵! 這也是編程誘人的地方.

    這篇文章僅供學(xué)jsf組件制作的朋友參考,如果你已經(jīng)是高手,或者你發(fā)現(xiàn)有什么不對(duì)的地方歡迎拍磚,批評(píng)指正,共同交流學(xué)習(xí)!QQ: 31703299

    QFaces相關(guān)完整示例下載



    - huliqing@huliqing.name
    - http://www.huliqing.name

    posted on 2008-11-30 23:41 huliqing 閱讀(4333) 評(píng)論(4)  編輯  收藏 所屬分類: JSF

    評(píng)論

    # re: 一個(gè)帶有Ajax功能的JSF組件的完整詳細(xì)開(kāi)發(fā)過(guò)程 2008-12-03 09:15 taijh

    謝謝分享  回復(fù)  更多評(píng)論   

    # re: 一個(gè)帶有Ajax功能的JSF組件的完整詳細(xì)開(kāi)發(fā)過(guò)程[未登錄](méi) 2009-04-29 19:26 IceRao

    感謝。不錯(cuò)的文章。  回復(fù)  更多評(píng)論   

    # re: 一個(gè)帶有Ajax功能的JSF組件的完整詳細(xì)開(kāi)發(fā)過(guò)程 2009-04-29 22:56 huliqing

    @IceRao
    謝謝關(guān)注:)
    QFaces在1.4版之后,取消了對(duì)jsp的支持,現(xiàn)在必須使用facelets,因?yàn)閒acelets與JSF才是絕配,所以該組件的制作在1.4后的版本是不能運(yùn)行的。但是在facelets下的制作過(guò)程與這個(gè)是基本上一樣的,并且更簡(jiǎn)單。
    為什么會(huì)取消對(duì)jsp的支持,主要是考慮到精力有限,并且在雙支持的情況下往往顧此失彼,所以希望集中精力做好facelets,并且一般使用JSF的,都強(qiáng)烈建議配合facelets視圖技術(shù)。
      回復(fù)  更多評(píng)論   

    # sss 2014-07-09 11:38 sssssss

    sssssssssssssssssssssss  回復(fù)  更多評(píng)論   

    導(dǎo)航

    統(tǒng)計(jì)

    公告

    文章原創(chuàng),歡迎轉(zhuǎn)載
    ——轉(zhuǎn)載請(qǐng)注明出處及原文鏈接

    隨筆分類(60)

    隨筆檔案(33)

    最新評(píng)論

    評(píng)論排行榜

    主站蜘蛛池模板: 免费吃奶摸下激烈视频| 国产亚洲sss在线播放| 成年网在线观看免费观看网址| 大陆一级毛片免费视频观看i| 亚洲精品永久www忘忧草| 暖暖免费在线中文日本| 久久亚洲精品无码观看不卡| 国产91成人精品亚洲精品| 亚洲欧美日韩中文高清www777| 1000部免费啪啪十八未年禁止观看 | 亚洲性线免费观看视频成熟| 亚洲黄色免费观看| 性色午夜视频免费男人的天堂| 亚洲国产另类久久久精品黑人| 精品无码一级毛片免费视频观看 | 男男gay做爽爽免费视频| 午夜视频在线在免费| 久久亚洲国产最新网站| 在线免费观看色片| 亚洲日本中文字幕天天更新| 99视频在线精品免费观看6| 亚洲国产视频久久| 无码高潮少妇毛多水多水免费| 亚洲综合一区国产精品| 成人无遮挡毛片免费看| 亚洲熟妇成人精品一区| 好吊妞视频免费视频| 亚洲成a人无码亚洲成av无码| 日韩视频免费在线| 综合一区自拍亚洲综合图区| 免费看国产一级片| 一区免费在线观看| 亚洲中文字幕第一页在线 | 毛片免费视频播放| 色欲色欲天天天www亚洲伊| 国产又大又长又粗又硬的免费视频 | 91福利免费体验区观看区| 亚洲神级电影国语版| 中文字幕影片免费在线观看| 亚洲精品精华液一区二区| 四虎国产精品免费视|