一個帶有Ajax功能的JSF組件的完整詳細開發過程

              文章有點長,寫得比較詳細,有興趣與耐心開發JSF組件的就往下看吧,下面將詳細介紹一個標準JSF組件的制作過程,并且后面將使用QFaces將它升級為Ajax方式的組件(如果要升級為Ajax組件,請先安裝QFaces增強框架).如果你發現有任何問題或錯漏,請給予批評指正,相關的完整代碼在QFaces的Demo示例中,可以自行下載查看:

              QFaces相關完整示例下載

              現在先來看一下一個JSF標準組件所需要用到的一些文件:

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

          2.UIComponentTag - 組件的jsp標簽處理類,主要進行值綁定及方法綁定等.

          3.tld - 標簽庫描述符文件,主要用于注冊組件的可用屬性等.

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

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

          現在我們來一步一步創建一個組件吧,暫且把這個組件的名字取為:Hello

          步驟1.創建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) {
                  
          // 后面我們將實現這個方法
              }

          }

              為了簡單起見,我們繼承了比較基礎的UIComponentBase 同時實現QFaces中的Ajax接口,Ajax接口需要實現兩個方法:ajaxInvokeOnPost ajaxInvokeOnPost, 分別處理postget請求,可以選擇實現,后面我們將實現ajaxInvokeOnGet這個方法,因為這對性能很好,如果你只需要一個標準JSF組件,可以不實現這個接口.在這里我們需要先進行一些其它方面的工作:渲染組件

          為了渲染組件,我們需要覆蓋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) {
                  
          // 我們將實現這個方法
              }

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


          }

          你可以看到我們實現的encodeBegin方法,實際上只是在客戶端渲染一個input而已,如果渲染正常,應該在html代碼中輸出像這樣的東西:

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

          接著我們先確保這個組件能在頁面中正常渲染并顯示,所以我們先注冊一下這個組件,并看一下效果,后面再實現組件的Ajax功能.

          步驟2.創建UIComponentTag – HtmlHelloTag.java

           


          public class HtmlHelloTag extends UIComponentELTag{

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

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

          }


          這一步中我們只是創建了一個java類并擴展UIComponentELTag, 覆蓋了getComponentType, 這個方法會告訴JSP使用哪一個主類來處理頁面標簽.類似于一個橋梁作用,后面會看到這是如何聯系到我們的主類HtmlHello.java的.

          getRendererType方法只返回null, 因為我們的組件主類HtmlHello會自行渲染.所以不需要其它渲染類.

          好了,HtmlHelloTag.java就這樣簡單,我們暫時不需要其他屬性(idrendered屬性默認已經有了,我們只要在tld文件中登記一下就可以),接著我們來將這個HtmlHelloTag注冊到tld文件中.


          步驟3.創建TLD標簽庫描述符文件 – 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>在這里登記標簽庫的名稱,版本,以及頁面引用時指定的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這個文件的名稱并沒有什么特殊的或需要約定的規則,把它直接放在WEB-INF文件夾下就可以了,JSF會自己去找到它.

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

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

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

          步驟4.將組件注冊到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文件中,我們注冊了前面創建的組件HtmlHello. <component-class>中指定了這個組件的主類的完全限定類名,<component-type>指定了這個組件的類型,實際上你可以使用其它自定的component-type,但是這個名稱必須與HtmlHelloTag.java中的方法:getComponentType所返回的名稱是一致的:

          public String getComponentType() {

                  return "demo.component.HtmlHello";

              }

          tmlHelloTag.java就是這樣聯系到這個組件的主類的。

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

          步驟5.先測試一下這個組件

          接著,我們先創建一個jsp頁面HelloDemo.jsp來測試一下新創建的組件,


          然后引入我們自定義的標簽庫,uri需要與我們在tld中定義的相同。

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


          這時當我們打入“<m”的時候jsp已經有了新定義組件的一些提示,下面看一下組件是否可以正常顯示,以下是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>


          可以看到組件已經可以正常的顯示了, 簡單的顯示了一個input,雖然確實非常簡單,并且幾乎沒有一點作用。不過這基本上就是一個標準JSF組件的創建過程,知道了原理之后我們就可以擴展出更多更高級的功能了。如果你只需要一個標準組件,那么到這一步就可以了.

          接下來我們將使用QFaces給組件增加Ajax的功能,提高用戶體驗。

          步驟6Ajax擴展 創建javascript文件 HtmlHello.js

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


          接著開始編寫這個js腳本,敲入如下的ajax請求代碼,后面你會知道組件是如何觸發這個腳本的.


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

          一些解釋:

          QFaces是我自定義的一個javascript類,可以方便處理ajax請求,已經簡化掉了很多幾乎沒有作用,或經常重復多余的代碼.這個類是如何引入的,后面會在組件的渲染中介紹.(你可以直接解開QFacesjar文件,從中找到這個js進行一些修改或許對你有用)

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

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

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

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

          2.       put()方法:可以很方便的設置傳遞參數,經過改造看起來很像java?。?/span>ap類的put方法.

          3.       setProcess(function):設置回調時的處理函數,在這里我們直接將Ajax帶回來的數據alert出來.

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

          因為get方法中框架使用了反射機制處理請求,所以需要知道是哪一個組件類發起的請求,并調用相應的處理方法(ajaxInvokeOnGet),但是Post方法卻是通過clientId來查找組件,并調用相應的處理方法(ajaxInvokeOnPost).

          Post方法性能較差,因為他會傳遞整個組件樹的狀態信息,并進行恢復視圖等處理.在我的多次測試中,這個階段幾乎至少要花掉約20毫秒的時間,如果頁面視圖足夠復雜可能花費的時間更多,但是Get方法不需要這個階段,它不需要跑任何生命周期,就好像你寫servletFilter來處理這個請求一樣.

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

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

          5.       QFaces.getComponent(“id”) 獲取頁面組件,為什么不使用document.getElementById(“id”)? 有時候你可能會發現某些瀏覽器下無法正常通過id獲取頁面組件,所以定義了這個方法,更好的兼容多瀏覽器.

          步驟7Ajax擴展 讓組件UIComponent觸發js

          現在開始升級一下前面創建的組件主類HtmlHello.java,讓它能觸發js調用,并進行ajax請求.


          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) {
                  
          // 我們將實現這個方法
              }

              @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函數用于組件的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");
              }

          }

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

          你可能會擔心多個組件同時在頁面的時候會導致重復加載js資源的問題,不過這個問題QFaces已經作了處理.

          現在先來測試一下組件是否可以正常的觸發這個js函數吧,稍微修改一下: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();
          }


          可以看到正常的觸發了這個函數,顯示了組件傳遞給jsclientIdcomponentClass

          現在重新修改回正常的js請求,并進行下一步Ajax請求的最終應答處理:


          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擴展 讓組件UIComponent響應Ajax請求

           

          現在我們開始處理Ajax請求的響應,回到組件主類HtmlHello.java來實現最初的方法ajaxInvokeOnGet, 下面是響應的方法實現:

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

              }

          你可以看到這個方法很簡單,取回了我們通過js發送過來的參數myname的值,并組織新值message,然后使用QFacesResponseHTML方法直接響應這個字符串.當然你也可以從FacesContext中獲得response對象進行自定義響應.現在看一下最終效果截圖:


          在輸入了一些信息之后,焦點離開組件,彈出了我們最終想要的效果!這已經是一個完整的帶有Ajax功能的組件了.但它的復用性并不好,因為我們硬編碼了Ajax響應.接下來的"進一步升級"會讓組件支持BackingBean方法綁定.使它可以進行重用.如果你有興趣就繼續往下看.

          3. 進一步升級?。摻ㄒ粋€可重用的Ajax組件

          現在先簡單回顧一下上面整個組件的制作過程,及處理流程:

          制作過程

          1.創建組件主類HtmlHello.java ->

          2.創建標簽屬性處理類HtmlHelloTag.java ->

          3.創建tld標簽描述符定義標簽庫,并將HtmlHelloTag.java注冊到其中 ->

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

          5.測試組件可以正常渲染并運行 ->

          6.(升級)創建js文件HtmlHello.js ->

          7.(升級)讓組件能裝載js并觸發jsajax請求 ->

          8.(升級)讓組件響應Ajax請求

          處理流程

          1.JSP頁面發現組件標簽<mc:hello /> ->

          2.JSF根據tld中定義的TagHtmlHelloTag.java來設置相應標簽屬性的值 ->

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

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

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

          6.頁面逞現,input輸入信息并離開焦點后觸發js : qfaces_demo_hello進行Ajax請求 ->

          7.QFaces根據請求的參數componentClass確定相應的處理類HtmlHello.java

          8.QFaces調用HtmlHello.javaajaxInvokeOnGet進行Ajax的響應.

          現在開始升級方法綁定,為了節省篇幅,后面的敘述及部驟可能不會太過詳細,但代碼仍是完整的.我們將使組件可以綁定一個這樣的方法:

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

          這個方法將獲取用戶輸入組件的值,同時用Ajax返回一些提示或驗證信息,使用方法像這樣

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

          1.       升級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>在這里登記標簽庫的名稱,版本,以及頁面引用時指定的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>

          現在我們在tld文件中注冊了一個新的屬性showMessage,他綁定了一個這樣的方法:

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

          2.       升級組件主類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); 
                  // 取得方法綁定的表達式
                  String messageExp = (this.showMessage != null ? 
                              
          this.showMessage.getExpressionString() : null
          );
                  
                  
          // 組織js函數用于組件的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("'"); // 增加傳遞的參數
                  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.       升級 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) { // 設置組件的方法綁定
                      ((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.       升級 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); // 傳遞方法綁定的表達式
              var process = function () {
                  alert(obj.request.responseText);
              }
              obj.setProcess(process);
              obj.get();
          }

          5.       升級組件主類的響應處理

          現在升級一下主類的ajaxInvokeOnGet使它能處理方法綁定.

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

          6.       新建BackingBean – DemoBean.java

          現在新建一個backingBean – DemoBean.java 并增加一個方法進行測試

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

          7.       最終測試


          <%@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>

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

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

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

          這篇文章僅供學jsf組件制作的朋友參考,如果你已經是高手,或者你發現有什么不對的地方歡迎拍磚,批評指正,共同交流學習!QQ: 31703299

          QFaces相關完整示例下載



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

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

          評論

          # re: 一個帶有Ajax功能的JSF組件的完整詳細開發過程 2008-12-03 09:15 taijh

          謝謝分享  回復  更多評論   

          # re: 一個帶有Ajax功能的JSF組件的完整詳細開發過程[未登錄] 2009-04-29 19:26 IceRao

          感謝。不錯的文章。  回復  更多評論   

          # re: 一個帶有Ajax功能的JSF組件的完整詳細開發過程 2009-04-29 22:56 huliqing

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

          # sss 2014-07-09 11:38 sssssss

          sssssssssssssssssssssss  回復  更多評論   

          導航

          統計

          公告

          文章原創,歡迎轉載
          ——轉載請注明出處及原文鏈接

          隨筆分類(60)

          隨筆檔案(33)

          最新評論

          評論排行榜

          主站蜘蛛池模板: 丰都县| 阿合奇县| 土默特左旗| 砚山县| 延吉市| 泸水县| 北碚区| 成都市| 湘潭市| 樟树市| 固镇县| 朝阳县| 大荔县| 禹州市| 东乡县| 唐海县| 镇平县| 连山| 宝应县| 兰坪| 乾安县| 亚东县| 莱西市| 崇州市| 同仁县| 大厂| 绥芬河市| 炎陵县| 渝北区| 汕头市| 乐至县| 工布江达县| 石嘴山市| 淮安市| 句容市| 彰化市| 北辰区| 昭通市| 自贡市| 奉贤区| 新竹县|