隨筆-33  評論-1965  文章-0  trackbacks-0

上一篇文章,我大概地介紹一下基于Faceslet的JSF頁面端的構成。接下來,是時候說一下后臺邏輯的實現啦。JSF的頁面邏輯是由Managed Bean(姑且譯為托管BEAN)實現。所謂的“Managed Bean”就是指一些由JSF運行時(Runtime)創建與管理的普通Java對象(潮流一點的叫法——POJO)。

標準JSF中Managed Bean

標準的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相信不用我怎么講解大家也知道其作用啦。定義一個BEAN,無論是在Spring、EJB還其它的BEAN容器(Container)中,無非都是這幾個元素:BEAN的名稱(或者標識,ID)、JAVA類型和作用域。JSF的Managed Bean有四個作用域,如下表所示:

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

可能大家對“none”作用域比較陌生,舉個例子可能會好理解一點:

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

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

Seam中的Web Bean(相當于Managed Bean)

標準JSF的Managed Bean存在不少缺點:

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

有監于此,Seam對JSF進行了擴展,并進而起草了Web Bean標準(Web Bean還在BETA階段,坦白的說我也不是很了解)。下面我們就來學習一下Seam的Managed Bean(官方文檔中叫Component)。在這方面Seam與標準JSF有如下不同:

  1. Seam的Component既可以通過XML配置,又可以通過Annotation的方式配置。我個人比較偏愛Annotation的方式,方便快捷,能夠提高工作效率。XML方式有一個好處就是可以集中管理,但是因為Managed Bean配置相對比較穩定,不會經常修改,所以XML優勢并不會太明顯;
  2. 更豐富的作用域(Seam中稱為上下文Context),Seam有6種上下文可?。何拮刺⊿tateless Context)、事件(Event Context,或者Request Context)、頁面(Page Context)、對話(Conversation Context)、會話(Session Context)、業務流(Business Process Context)和應用程序(Application Context);
  3. Seam引入一種雙向注入(Binjection)的方式。所謂的雙向注入就是可以將上下文中的Bean注入到另一個Bean中,又或者將Bean中的屬性(Property)直接發布在上下文中;
  4. Seam的Compoenet可以直接使用EJB 3.0的Bean。

下面我們看一個簡單的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。除此之外,并沒有什么特別的地方,所以正是這兩個Annotation使HelloWB成為一個可以被SEAM的運行時識別的Component。Name用于定義Component的名稱,是必須的;Scope則用于定義Component的作用域,是可選的,默認值為短對話(Short Conversation)。在本例中,HelloWB的作用域是Page。Page與Conversation都Seam的杰作,在標準JSF是沒有的。而且,這兩個作用域是比較常用,我個人比較熱衷于Page作用域,所以在這里先談一下Page。

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

另外,一些JSF專家都推薦一種叫Backing Bean的風格。所謂的Backing Bean就是指一個JSF頁面對應一個Managed Bean處理頁面邏輯。Page作用域非常適用這種情況,因為它是與頁面一起序列化(Serialize)到瀏覽器或保存在Session中。如果大家還是不太明白的話,請看以下的XHTML代碼。

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "//www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 3 
 4 <html xmlns="//www.w3.org/1999/xhtml" xmlns:h="//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>

發布運行上述代碼,大家可以看如下頁面。

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

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

小結

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

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

評論:
# re: Seam的頁面邏輯實現 2009-04-22 20:41 | koumei
配置文件有麻煩的時候,也有便利的時候:有配置文件就不會因為某些小的更改而重新build過項目。  回復  更多評論
  
# re: Seam的頁面邏輯實現 2009-04-24 16:26 | yxc
雖然現在還不懂,關注中  回復  更多評論
  
# re: Seam的頁面邏輯實現 2009-05-12 14:04 | peterlee
@yxc
希望這里能成為我技術修煉的好地方!  回復  更多評論
  
# re: Seam的頁面邏輯實現 2009-05-15 00:05 | 新人王
MAX 真的要贊你,請問你在哪個QQ群,交流一下!qq:514251682  回復  更多評論
  
# re: Seam的頁面邏輯實現 2009-06-08 21:29 | java_faver
感謝max!寫得非常棒,希望快快更新,一直關注ing!  回復  更多評論
  
# re: Seam的頁面邏輯實現 2009-06-09 20:05 | paopao
是啊 max 期待更新 最近也在學seam呢...  回復  更多評論
  
# re: Seam的頁面邏輯實現 2009-06-13 18:52 | [email protected]
<TABLE cellSpacing="1" cellPadding="2" align="center">
<TR>
<TD width="75%" height="21">
<SPAN class="style1">賬號:</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>驗證碼:</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>  回復  更多評論
  
# re: Seam的頁面邏輯實現 2009-06-13 19:01 | [email protected]
親愛的Max:
您能不能告訴我,你上邊的文章中的嵌入的代碼:有紅色有藍色的 !這是怎么嵌入進去的????能告訴我嗎?發我郵箱里邊!或者有知道的加我QQ:45522956  回復  更多評論
  
# re: Seam的頁面邏輯實現 2010-09-03 18:27 | 南通SEO
不錯受教了。  回復  更多評論
  
# re: Seam的頁面邏輯實現 2010-09-26 10:54 | lw
期待seam系列續集......呵呵  回復  更多評論
  

只有注冊用戶登錄后才能發表評論。


網站導航:
 
{ganrao} 20选8全中是多少钱 江苏体彩e球彩下载 老版六宝典2014 苹果琼崖麻将下载安装 美女捕鱼棋牌背景图 北京麻将官方下载 一分钟一期的彩票骗局 网络正规捕鱼赢钱游戏 天才麻将少女 pk10高手单期计 英超29轮比赛时间 广西友玩麻将下载安装 中特网一肖一码com 下载免费打麻将 悬赏猫和众人帮哪个好 德甲联赛积分榜