隨筆-34  評(píng)論-1965  文章-0  trackbacks-0

          上一篇文章,我大概地介紹一下基于Faceslet的JSF頁面端的構(gòu)成。接下來,是時(shí)候說一下后臺(tái)邏輯的實(shí)現(xiàn)啦。JSF的頁面邏輯是由Managed Bean(姑且譯為托管BEAN)實(shí)現(xiàn)。所謂的“Managed Bean”就是指一些由JSF運(yùn)行時(shí)(Runtime)創(chuàng)建與管理的普通Java對(duì)象(潮流一點(diǎn)的叫法——POJO)。

          標(biāo)準(zhǔn)JSF中Managed Bean

          標(biāo)準(zhǔn)的JSF中Managed Bean是在faces-config.xml中通過XML定義的。例如:

          <managed-bean>
              
          <managed-bean-name>helloBean</managed-bean-name>
              
          <managed-bean-class>
                  net.blogjava.max.seam.HelloBean
              
          </managed-bean-class>
              
          <managed-bean-scope>request</managed-bean-scope>
          </managed-bean>

          這些XML相信不用我怎么講解大家也知道其作用啦。定義一個(gè)BEAN,無論是在Spring、EJB還其它的BEAN容器(Container)中,無非都是這幾個(gè)元素:BEAN的名稱(或者標(biāo)識(shí),ID)、JAVA類型和作用域。JSF的Managed Bean有四個(gè)作用域,如下表所示:

          作用域 描述
          none 作用域是none的Managed Bean通常是定義一些公用的BEAN,它們的創(chuàng)建與存儲(chǔ)依賴于引用它的BEAN
          request 在單一的HTTP請(qǐng)求(Request)中被創(chuàng)建和保持有效
          session 在HTTP的會(huì)話(Session)中被創(chuàng)建和保持有效,可以跨請(qǐng)求
          application 存儲(chǔ)WEB應(yīng)用的Application上下文中,對(duì)于所有的請(qǐng)求和會(huì)話可見

          可能大家對(duì)“none”作用域比較陌生,舉個(gè)例子可能會(huì)好理解一點(diǎn):

          <managed-bean>
             
          <managed-bean-name>helloBean</managed-bean-name>
             
          <managed-bean-class>
                com.pccw.jsftraining.managedbean.HelloBean
             
          </managed-bean-class>
             
          <managed-bean-scope>request</managed-bean-scope>
             
          <managed-property>
                
          <property-name>messageFromOtherBean</property-name>
                
          <property-class>java.lang.String</property-class>
                
          <value>#{messageBean}</value>
             
          </managed-property>
          </managed-bean>
          <managed-bean>
             
          <managed-bean-name>messageBean</managed-bean-name>
             
          <managed-bean-class>java.lang.String</managed-bean-class>
             
          <managed-bean-scope>none</managed-bean-scope>
             
          <value>Hello World from Another Bean!</value>
          </managed-bean>

          這個(gè)例子定義了一個(gè)名為messageBean、作用域是none的Managed Bean,然后它被注入名為messageBean、作用域是request的Managed Bean中。因此,這個(gè)messageBean的作用域會(huì)跟隨helloBean,同為request。另外值得一提的是,上例同樣展示了如何在一個(gè)Managed Bean初始其屬性(Property)的值,如何引用其它的Managed Bean。

          Seam中的Web Bean(相當(dāng)于Managed Bean)

          標(biāo)準(zhǔn)JSF的Managed Bean存在不少缺點(diǎn):

          1. 必須通過XML進(jìn)行配置,過于麻煩;
          2. 貧乏的作用域,上文提及標(biāo)準(zhǔn)的JSF的Managed Bean只有四種作用域:none、request、session和application。由于JSF對(duì)狀態(tài)的依賴比較強(qiáng),經(jīng)常需要在請(qǐng)求之間保存應(yīng)用的狀態(tài),所以很多時(shí)候我們時(shí)候都不得不使用Session作用域的Managed Bean。但是眾所周知,過多地使用Session會(huì)帶來很多問題,如容易造成內(nèi)存耗盡,難于集群(Cluster)等。

          有監(jiān)于此,Seam對(duì)JSF進(jìn)行了擴(kuò)展,并進(jìn)而起草了Web Bean標(biāo)準(zhǔn)(Web Bean還在BETA階段,坦白的說我也不是很了解)。下面我們就來學(xué)習(xí)一下Seam的Managed Bean(官方文檔中叫Component)。在這方面Seam與標(biāo)準(zhǔn)JSF有如下不同:

          1. Seam的Component既可以通過XML配置,又可以通過Annotation的方式配置。我個(gè)人比較偏愛Annotation的方式,方便快捷,能夠提高工作效率。XML方式有一個(gè)好處就是可以集中管理,但是因?yàn)镸anaged Bean配置相對(duì)比較穩(wěn)定,不會(huì)經(jīng)常修改,所以XML優(yōu)勢(shì)并不會(huì)太明顯;
          2. 更豐富的作用域(Seam中稱為上下文Context),Seam有6種上下文可選:無狀態(tài)(Stateless Context)、事件(Event Context,或者Request Context)、頁面(Page Context)、對(duì)話(Conversation Context)、會(huì)話(Session Context)、業(yè)務(wù)流(Business Process Context)和應(yīng)用程序(Application Context);
          3. Seam引入一種雙向注入(Binjection)的方式。所謂的雙向注入就是可以將上下文中的Bean注入到另一個(gè)Bean中,又或者將Bean中的屬性(Property)直接發(fā)布在上下文中;
          4. Seam的Compoenet可以直接使用EJB 3.0的Bean。

          下面我們看一個(gè)簡(jiǎn)單的Component的定義的例子,

           1 package net.blogjava.max.hello.session;
           2 
           3 import org.jboss.seam.ScopeType;
           4 import org.jboss.seam.annotations.Name;
           5 import org.jboss.seam.annotations.Scope;
           6 
           7 @Name("helloWB")
           8 @Scope(ScopeType.PAGE)
           9 public class HelloWB {
          10     private String name;
          11     private String message;
          12 
          13     public String getName() {
          14         return name;
          15     }
          16 
          17     public void setName(String name) {
          18         this.name = name;
          19     }
          20 
          21     public String getMessage() {
          22         return message;
          23     }
          24 
          25     public void setMessage(String message) {
          26         this.message = message;
          27     }
          28 
          29     public void sayHello() {
          30         message = "Hello, " + name + "!";
          31     }
          32     
          33     public void anotherEvent() {
          34         System.out.println("Another request is coming");
          35     }
          36 }

          通過上述代碼,大家可以看到有兩句Annotation定義——Name和Scope。除此之外,并沒有什么特別的地方,所以正是這兩個(gè)Annotation使HelloWB成為一個(gè)可以被SEAM的運(yùn)行時(shí)識(shí)別的Component。Name用于定義Component的名稱,是必須的;Scope則用于定義Component的作用域,是可選的,默認(rèn)值為短對(duì)話(Short Conversation)。在本例中,HelloWB的作用域是Page。Page與Conversation都Seam的杰作,在標(biāo)準(zhǔn)JSF是沒有的。而且,這兩個(gè)作用域是比較常用,我個(gè)人比較熱衷于Page作用域,所以在這里先談一下Page。

          正如我前面所說“JSF對(duì)狀態(tài)的依賴比較強(qiáng)...”,造成我們對(duì)Session的依賴,引起了很多問題。Page很大程度上解決了這個(gè)問題,它可以跨請(qǐng)求存活,只要該請(qǐng)求不是“新的”。什么請(qǐng)求是“新的”請(qǐng)求呢?要回答這個(gè)問題,先要搞清楚什么是“POST-BACK”。學(xué)過ASP.NET的朋友可能對(duì)POST-BACK概念比較熟悉,沒學(xué)過的話不要緊。POST-BACK并不是什么深?yuàn)W的東西,所謂的POST-BACK,就是指用戶按下頁面上的某個(gè)按鈕或表單控件,將表單數(shù)據(jù)發(fā)送回到頁面自身的URL。相反,如果用戶是通過在地址欄中輸入U(xiǎn)RL,或通過點(diǎn)擊頁面的鏈接訪問頁面,則這個(gè)請(qǐng)求就是一個(gè)NON-POST-BACK的請(qǐng)求,也即是一個(gè)新的請(qǐng)求。

          另外,一些JSF專家都推薦一種叫Backing Bean的風(fēng)格。所謂的Backing Bean就是指一個(gè)JSF頁面對(duì)應(yīng)一個(gè)Managed Bean處理頁面邏輯。Page作用域非常適用這種情況,因?yàn)樗桥c頁面一起序列化(Serialize)到瀏覽器或保存在Session中。如果大家還是不太明白的話,請(qǐng)看以下的XHTML代碼。

           1 <?xml version="1.0" encoding="utf-8"?>
           2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
           3 
           4 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html">
           5     <head>
           6         <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
           7         <title>
           8             Hello World
           9         </title>
          10     </head>
          11     <body>
          12         <h:form>
          13             <h:outputLabel value="Name: " for="itName" />
          14             <h:inputText id="itName" value="#{helloWB.name}" />
          15             <h:commandButton action="#{helloWB.sayHello}" value="Say Hello" />
          16             <h:commandButton action="#{helloWB.anotherEvent}" value="Another Reqeust" />
          17             <hr />
          18             <h2>
          19                 <h:outputText value="#{helloWB.message}" />
          20             </h2>
          21         </h:form>
          22     </body>
          23 </html>

          發(fā)布運(yùn)行上述代碼,大家可以看如下頁面。

          在輸入框中鍵入“max”,點(diǎn)擊“Say Hello”按鈕,將請(qǐng)求POST-BACK到Seam的組件中,由于按鈕注冊(cè)了組件的監(jiān)聽方法,所以HelloWB的sayHello方法會(huì)被調(diào)用。它將通過值綁定所得的name與“Hello”和“!”串起來,賦給message屬性。因此,響應(yīng)頁面會(huì)如下圖所示:

          這時(shí)候,大家可以再點(diǎn)擊“Another Request”按鈕,出現(xiàn)的結(jié)果與上圖一樣。這就說明雖然發(fā)生了第二次請(qǐng)求,name與message的同樣保持上一次的值。然后,大家可以再試下復(fù)制頁面地址,粘貼到新窗口或新選項(xiàng)卡(TAB)的地址欄中,按下ENTER。你會(huì)發(fā)現(xiàn)頁面的被重置回到最初的狀態(tài)。這個(gè)例子很好地演示了POST-BACK請(qǐng)求與NON-POST-BACK請(qǐng)求的區(qū)別。

          小結(jié)

          本文粗略地介紹了一下JSF的頁面邏輯處理組件——Managed Bean,還有很多關(guān)于Seam的組件知識(shí)如Bijection和Conversation等還沒有介紹,只有留待以后文章了。

          posted on 2009-04-20 23:47 Max 閱讀(4711) 評(píng)論(10)  編輯  收藏 所屬分類: Seam系列

          評(píng)論:
          # re: Seam的頁面邏輯實(shí)現(xiàn) 2009-04-22 20:41 | koumei
          配置文件有麻煩的時(shí)候,也有便利的時(shí)候:有配置文件就不會(huì)因?yàn)槟承┬〉母亩匦耣uild過項(xiàng)目。  回復(fù)  更多評(píng)論
            
          # re: Seam的頁面邏輯實(shí)現(xiàn) 2009-04-24 16:26 | yxc
          雖然現(xiàn)在還不懂,關(guān)注中  回復(fù)  更多評(píng)論
            
          # re: Seam的頁面邏輯實(shí)現(xiàn) 2009-05-12 14:04 | peterlee
          @yxc
          希望這里能成為我技術(shù)修煉的好地方!  回復(fù)  更多評(píng)論
            
          # re: Seam的頁面邏輯實(shí)現(xiàn) 2009-05-15 00:05 | 新人王
          MAX 真的要贊你,請(qǐng)問你在哪個(gè)QQ群,交流一下!qq:514251682  回復(fù)  更多評(píng)論
            
          # re: Seam的頁面邏輯實(shí)現(xiàn) 2009-06-08 21:29 | java_faver
          感謝max!寫得非常棒,希望快快更新,一直關(guān)注ing!  回復(fù)  更多評(píng)論
            
          # re: Seam的頁面邏輯實(shí)現(xiàn) 2009-06-09 20:05 | paopao
          是啊 max 期待更新 最近也在學(xué)seam呢...  回復(fù)  更多評(píng)論
            
          # re: Seam的頁面邏輯實(shí)現(xiàn) 2009-06-13 18:52 | liushi20008@sina.com
          <TABLE cellSpacing="1" cellPadding="2" align="center">
          <TR>
          <TD width="75%" height="21">
          <SPAN class="style1">賬號(hào):</SPAN>
          <html:text property="users.UNickName" styleId="txtName" size="15"/><div id="divName"></div><html:errors property="txtName" />
          </TD>
          </TR>
          <TR>
          <TD height=20>
          <SPAN class=style1>密碼:</SPAN>
          <html:password property="users.UPassWord" redisplay="true" styleId="txtPwd" size="17"/><div id="divPwd"></div>
          </TD>
          </TR>
          <TR>
          <TD>
          <SPAN class=style1>驗(yàn)證碼:</SPAN>
          <html:text property="logincode" size="13" styleId="txtCode"/><html:errors property="txtCode" />
          <img id="yzmImg" src="CodeImages" onclick="this.src='CodeImages'"/><a href="javascript:changeImage();">換一張</a>
          </TD>
          </TR>
          </TBODY>
          </TABLE>  回復(fù)  更多評(píng)論
            
          # re: Seam的頁面邏輯實(shí)現(xiàn) 2009-06-13 19:01 | liushi20008@sina.com
          親愛的Max:
          您能不能告訴我,你上邊的文章中的嵌入的代碼:有紅色有藍(lán)色的 !這是怎么嵌入進(jìn)去的?。浚磕芨嬖V我嗎?發(fā)我郵箱里邊!或者有知道的加我QQ:45522956  回復(fù)  更多評(píng)論
            
          # re: Seam的頁面邏輯實(shí)現(xiàn) 2010-09-03 18:27 | 南通SEO
          不錯(cuò)受教了。  回復(fù)  更多評(píng)論
            
          # re: Seam的頁面邏輯實(shí)現(xiàn) 2010-09-26 10:54 | lw
          期待seam系列續(xù)集......呵呵  回復(fù)  更多評(píng)論
            

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 淮安市| 渭南市| 溧水县| 麦盖提县| 团风县| 隆回县| 沾化县| 阜南县| 石棉县| 杭锦旗| 象山县| 贵州省| 迁安市| 苏尼特左旗| 新乐市| 平阴县| 丰城市| 沧源| 林甸县| 布尔津县| 蓬莱市| 安仁县| 金塔县| 得荣县| 蓬溪县| 从江县| 马尔康县| 四会市| 南郑县| 隆安县| 信丰县| 靖州| 黄骅市| 改则县| 高密市| 康马县| 遂昌县| 洛南县| 枣庄市| 澄城县| 东辽县|