J2EE寵物商店
作者:◇ 谷和啟 ? 來(lái)源:CSDN
 

 J2EE 是Java技術(shù)在企業(yè)運(yùn)算上的應(yīng)用,它包含多種運(yùn)算標(biāo)準(zhǔn),如EJB組件架構(gòu)、JDBC數(shù)據(jù)庫(kù)運(yùn)算、JMS信息傳遞、Java Servlets/JSP等Web組件程序等,功能強(qiáng)大且內(nèi)容博大精深。為了讓使用者可以有一個(gè)設(shè)計(jì)J2EE架構(gòu)應(yīng)用程序的模板,Sun做出一套系統(tǒng)名為“Java寵物商店(Pet Store)”。這個(gè)網(wǎng)上寵物店的范例是針對(duì)已經(jīng)熟悉Java程序設(shè)計(jì)和J2EE概念人員的。這個(gè)系統(tǒng)是使用正規(guī)方式設(shè)計(jì)出來(lái)的,使得使用J2EE架構(gòu)的人員有了一個(gè)參考的依據(jù)。這個(gè)范例一出來(lái),很快就被用來(lái)當(dāng)成比較各家J2EE兼容產(chǎn)品的依據(jù)。Oracle的J2EE Application Server(Oracle 9iAS)、BEA WebLogic Server、IBM WebSphere都有相應(yīng)的產(chǎn)品。Java標(biāo)準(zhǔn)的精神原本就是各家廠商合作制定技術(shù)標(biāo)準(zhǔn),然后再根據(jù)這個(gè)標(biāo)準(zhǔn)來(lái)評(píng)選出最優(yōu)產(chǎn)品。

  Java Pet Store使用的架構(gòu)設(shè)計(jì)就是所謂的MVC 設(shè)計(jì)模式。MVC是Model-View-Controller的簡(jiǎn)寫,是設(shè)計(jì)模式的一種,源自Smalltalk。MVC模式則是將對(duì)象分成三類,Model對(duì)象專門用來(lái)包裝應(yīng)用程序的狀態(tài),View用來(lái)負(fù)責(zé)屏幕上的展現(xiàn),Controller則負(fù)責(zé)定義應(yīng)用程序的各種動(dòng)作和反應(yīng)。Java寵物店系統(tǒng)利用MVC模式設(shè)計(jì)整個(gè)系統(tǒng)架構(gòu),將各層的對(duì)象清楚地分開。Java寵物店的目的是展示一個(gè)具有擴(kuò)充性的企業(yè)運(yùn)算架構(gòu),就是采用三層(3-Tiers)式設(shè)計(jì):資料展現(xiàn)層在最外面,中間是執(zhí)行企業(yè)運(yùn)算邏輯的中間層組件,后端就是單純存放資料的關(guān)系型數(shù)據(jù)庫(kù)。Java寵物店當(dāng)初的用意也只是當(dāng)成一個(gè)J2EE架構(gòu)設(shè)計(jì)的模板,并沒有特別針對(duì)加速執(zhí)行效能作額外的設(shè)計(jì)。

系統(tǒng)構(gòu)架與寵物商店簡(jiǎn)介

  系統(tǒng)構(gòu)架

  Pet Store網(wǎng)站系統(tǒng)采用松耦合的設(shè)計(jì)架構(gòu),可以和多個(gè)數(shù)據(jù)源、EIS進(jìn)行交互。這個(gè)例子共分成4個(gè)部分:

  1.Web購(gòu)物站點(diǎn);

  2.管理部分,包括銷售統(tǒng)計(jì)、手工接受/拒絕訂單;

  3.訂單處理,包括以下4部分內(nèi)容:

   ◆ 通過JMS接受/處理訂單消息;

   ◆ 用Java Mail來(lái)通知客戶;

   ◆ 通過JMS發(fā)訂單給供應(yīng)商;

  ◆ 維護(hù)訂單數(shù)據(jù)庫(kù)。

  4.供應(yīng)商,此部分包括以下內(nèi)容:

   ◆ 通過JMS接受訂單;

  ◆ 派送貨物給用戶;

  ◆ 提供一個(gè)基于Web的庫(kù)存管理;

  ◆ 維護(hù)庫(kù)存數(shù)據(jù)庫(kù)。

  寵物店網(wǎng)上商店功能

  通過瀏覽器可以訪問此商店。客戶通過瀏覽,可以把貨物放入購(gòu)物車,創(chuàng)建賬戶/登錄賬戶,創(chuàng)建訂單,然后通過信用卡支付。

  寵物商店結(jié)構(gòu)

  寵物店的網(wǎng)站服務(wù)是從上而下的。最上層是WAF(Web Application Framework)來(lái)控制應(yīng)用的屏幕跳轉(zhuǎn),產(chǎn)生視圖,然后調(diào)用商業(yè)組件來(lái)完成商業(yè)處理(如圖1所示)。



  圖1 Java Pet Store 結(jié)構(gòu)

  WAF提供了許多Web應(yīng)用所需的服務(wù),包括請(qǐng)求的過濾和分發(fā)、模板視圖的產(chǎn)生、一系列可重用的Taglib,以及屏幕流程控制等。應(yīng)用組件封裝了處理的邏輯,它們代表了商業(yè)的數(shù)據(jù),并且操作這些商業(yè)數(shù)據(jù),實(shí)體EJB代表了商業(yè)實(shí)體,如客戶、地址、賬目。會(huì)話EJB提供了一些方法,如登陸一個(gè)用戶、輸出一個(gè)用戶、管理購(gòu)物車等。其它會(huì)話EJB提供了一些共同的方法,如產(chǎn)生唯一標(biāo)示符。傳統(tǒng)的JavaBean組件變成了值對(duì)象,用來(lái)在EJB組件和應(yīng)用間傳遞數(shù)據(jù)。XML文檔類則用來(lái)處理訂單信息。

  這個(gè)寵物店例子的WAF是對(duì)J2EE藍(lán)圖Web層規(guī)范的實(shí)現(xiàn)。一個(gè)Web層處理一般可以劃分成四步(如圖2所示):

  ◆ 解釋一個(gè)請(qǐng)求;

  ◆ 執(zhí)行一個(gè)商業(yè)邏輯處理;

  ◆ 選擇下一個(gè)視圖;

  ◆ 產(chǎn)生這個(gè)視圖。



  圖2 WAF的Web層處理

  寵物店模塊設(shè)計(jì)

  寵物店由一些獨(dú)立模塊組成:

  ◆ 控制模塊 它來(lái)分發(fā)請(qǐng)求到各個(gè)業(yè)務(wù)處理邏輯、控制屏幕跳轉(zhuǎn)、處理對(duì)應(yīng)的組件及用戶;

  ◆ 登錄和注冊(cè) 控制模塊由WAF實(shí)現(xiàn)和擴(kuò)展;

  ◆ 購(gòu)物車模塊 購(gòu)物車跟蹤用戶購(gòu)物過程;

  ◆ 登錄模塊 需要用戶登錄在某些頁(yè)面登錄;

  ◆ 消息模塊 從寵物店到等單中心用來(lái)異步傳輸訂單;

  ◆ 類別模塊 根據(jù)用戶查詢需求提供一個(gè)類別視圖;

  ◆ 客戶模塊 表示客戶信息,如地址、信用卡、聯(lián)系方式等(如圖3所示)。



  圖3 Java pet Store 模塊設(shè)計(jì)

  在圖3中,控制模塊控制所有的交互和執(zhí)行,每個(gè)用戶會(huì)話都有一個(gè)購(gòu)物車對(duì)應(yīng)。

  寵物店的組件

  1. EJB,代表了商業(yè)數(shù)據(jù)和執(zhí)行商業(yè)邏輯處理;

  2. JSP頁(yè)面, 定義了整個(gè)應(yīng)用的視圖框架模板(template.jsp)和模板組成的各個(gè)JSP文件,以及各種被引用的圖形文件;

  3. XML文件,用來(lái)定義屏幕、屏幕跳轉(zhuǎn)控制、綁定URL到某個(gè)HTML Action、定制signOn以及J2EE部署的部署XML文件;

  4. Servlet過慮器, 用來(lái)校驗(yàn)用戶安全的登陸和輸出的編碼;

  5. 異步信息發(fā)送組件,傳輸使用XML封裝的訂單到訂單處理中心;

  6. 一個(gè)安裝程序,用來(lái)產(chǎn)生例子數(shù)據(jù)庫(kù)。

分析寵物商店的應(yīng)用

下面就按照MVC架構(gòu)和層次化應(yīng)用模型來(lái)分析這個(gè)應(yīng)用。

模型—視圖—控制架構(gòu)

1.應(yīng)用模型劃分方法

分析一個(gè)實(shí)際應(yīng)用可以有三種劃分的方法:第一種劃分方法為模型—視圖—控制(MVC)架構(gòu)。這種方法把應(yīng)用分解成數(shù)據(jù)、顯示和控制三個(gè)部分。第二種劃分方法把應(yīng)用按照不同的角色劃分成不同的層次,分離客戶端、Web層、EJBs層和底端的數(shù)據(jù)層或遺留系統(tǒng)層,即J2EE應(yīng)用的層次劃分方法。第三種劃分是傳統(tǒng)的功能模塊劃分。

劃分的目的是使復(fù)雜的問題清晰化、條理化。每一種劃分雖然增加了額外的復(fù)雜性,但也有它的好處。MVC架構(gòu)為應(yīng)用組件提供一個(gè)靈活的、可重用的、易測(cè)試的、可擴(kuò)展的和清晰的設(shè)計(jì)角色。多層設(shè)計(jì)使實(shí)現(xiàn)技術(shù)的選擇靈活,同時(shí)具有可升級(jí)和可擴(kuò)展性。模塊化的設(shè)計(jì)把系統(tǒng)分解成小的直接模塊,可以進(jìn)行單獨(dú)分析、測(cè)試和理解。

現(xiàn)在企業(yè)級(jí)應(yīng)用與以前相比,要更多地支持使用不同類型接口的多類型用戶,例如在線商店需要為Web顧客提供HMTL主頁(yè)、為無(wú)線顧客提供XML主頁(yè)、為系統(tǒng)管理員提供JFC/Swing接口、為供應(yīng)商提供基于XML的Web服務(wù)等(見圖4)。



圖4 Java Pet Store 支持的各種類型用戶關(guān)系圖

當(dāng)開發(fā)一個(gè)支持單一類型客戶端的應(yīng)用時(shí),可以把數(shù)據(jù)訪問邏輯、顯示控制邏輯和接口邏輯交織在一起。但對(duì)于支持多類型客戶端的企業(yè)系統(tǒng)來(lái)說,這是很麻煩的。因此:

◆ 對(duì)于每種類型的客戶端接口,需開發(fā)不同的應(yīng)用;

◆ 每個(gè)應(yīng)用的非界面代碼是重復(fù)的,在實(shí)現(xiàn)、測(cè)試和維護(hù)方面需重復(fù)工作;

◆ 復(fù)制工作本身是昂貴的,因?yàn)榻缑媾c非界面代碼交織;

◆ 重復(fù)工作不可避免,而且是有缺陷而緩慢的。

2.使用模型—視圖—控制架構(gòu)

通過在J2EE應(yīng)用中使用模型—視圖—控制架構(gòu),把核心數(shù)據(jù)和數(shù)據(jù)訪問功能與使用這些功能的顯示控制邏輯分開,如圖5所示。這種分離允許多視圖共享同樣的企業(yè)數(shù)據(jù)模型。



圖5 MVC架構(gòu)

MVC架構(gòu)起源于Smalltalk,最初用來(lái)在傳統(tǒng)的圖形用戶界面模型中映射輸入、處理和輸出任務(wù)。然而,它可以直接用來(lái)映射多層企業(yè)應(yīng)用中的相關(guān)概念,具體概念介紹如下:

模型(Model)代表企業(yè)數(shù)據(jù)和業(yè)務(wù)規(guī)則,用來(lái)控制訪問和數(shù)據(jù)更新。模型是接近現(xiàn)實(shí)世界的服務(wù)軟件,因此現(xiàn)實(shí)世界的建模技術(shù)可以應(yīng)用模型。

視圖(View)代表模型的內(nèi)容。它通過模型訪問企業(yè)數(shù)據(jù)并指定這些數(shù)據(jù)的顯示。視圖負(fù)責(zé)模型狀態(tài)改變后呈現(xiàn)給用戶的數(shù)據(jù)也相應(yīng)改變。可以通過推(Push)模型實(shí)現(xiàn),即視圖在模型中注冊(cè)獲取更新指令,或者拉(Pull)模型,即由視圖負(fù)責(zé)在需要獲取最新數(shù)據(jù)的時(shí)候調(diào)用模型。

控制(Controller)把與視圖交互轉(zhuǎn)化成模型執(zhí)行的動(dòng)作。在獨(dú)立運(yùn)行的GUI客戶端,用戶交互可能是按鈕或菜單,而在Web應(yīng)用中是GET和POST HTTP請(qǐng)求。模型執(zhí)行的動(dòng)作包括激活業(yè)務(wù)處理進(jìn)程或改變模型狀態(tài)。以用戶交互和模型動(dòng)作結(jié)果為基礎(chǔ),控制通過選擇合適的視圖完成相應(yīng)功能。

MVC架構(gòu)有如下優(yōu)點(diǎn):

◆ 多視圖使用同一模型。模型與視圖分離允許多視圖使用同一企業(yè)模型。因此,企業(yè)級(jí)應(yīng)用模型組件容易實(shí)現(xiàn)、測(cè)試和維護(hù)。

◆ 容易支持新類型的客戶端。支持一個(gè)新類型的客戶端,只需寫一個(gè)視圖和控制,然后把它連到現(xiàn)存的企業(yè)模型中。

分析Java Pet Store應(yīng)用

視圖

視圖是用戶界面和應(yīng)用程序的接口。在Java Pet Store中,視圖在Web層實(shí)現(xiàn)。共有三種組件實(shí)現(xiàn)視圖:JSP頁(yè)面、JSP自定義標(biāo)記和JavaBean。視圖部分涉及到三方面內(nèi)容:

1.屏幕

屏幕是一個(gè)頁(yè)面顯示的所有內(nèi)容。根據(jù)需要,在ScreenDefinitions.jsp中定義如下屏幕:

																												
																														
Name:MAIN_SCREEN,DEFAULT_SCREEN
    Name:CATEGORY_SCREEN
    Name:SEARCH_SCREEN
    Name:PRODUCT_SCREEN
    Name:PRODUCT_DETAILS_SCREEN
    Name:CART_SCREEN
    Name:CHECKOUT_SCREEN
    Name:PLACEORDER_SCREEN
    Name:COMMIT_ORDER_SCREEN
    Name:SIGNIN_SCREEN
    Name:SIGNUP_SCREEN
																												
																										


2.模板

因?yàn)橐拐麄€(gè)網(wǎng)站的頁(yè)面具有相同的特征,如每個(gè)頁(yè)面都要有Logo、Banner等相同的元素,所以采用模板定義頁(yè)面的不同組成部分。本示例中定義的模板元素有footer.jsp、banner.jsp和index.jsp等。ScreenDefinitions.jsp定義好的屏幕包括這些模板元素,通過include指令包含到頁(yè)面中

3.視圖選擇

視圖的選擇是通過控制來(lái)完成的。控制根據(jù)實(shí)際情況分析用戶顯示視圖的ID,運(yùn)行模板把整個(gè)視圖顯示出來(lái),如圖6所示。



圖6 視圖選擇

模型

模型的狀態(tài)是視圖顯示的數(shù)據(jù)來(lái)源,也是控制的具體對(duì)象。在J2EE中,描述模型的狀態(tài)采用三種EJB:無(wú)狀態(tài)會(huì)話EJB、有狀態(tài)會(huì)話EJB和實(shí)體EJB。

1.輔助對(duì)象

有兩種主要的輔助對(duì)象:數(shù)據(jù)庫(kù)訪問對(duì)象和值對(duì)象。對(duì)于實(shí)體EJB來(lái)說,數(shù)據(jù)庫(kù)訪問對(duì)象封裝了數(shù)據(jù)庫(kù)訪問的方法,如AccountDAO等。對(duì)于所有EJB的屬性值,則都由一個(gè)值對(duì)象來(lái)封裝,如ShoppingCartModel、AccountModel等。

2.EJBs

本示例用到的EJBs如圖7所示。



圖7 Java Pet Store使用到的EJBs

3.模型狀態(tài)到視圖的綁定

一個(gè)模型對(duì)應(yīng)多個(gè)視圖,實(shí)現(xiàn)視圖的綁定方法是:ModelUpdateListener和ModelUpdateNotifier實(shí)現(xiàn)了一種注冊(cè)-監(jiān)聽模式,通過調(diào)用監(jiān)聽器的performUpdate方法來(lái)使視圖得到更新。例如:

																																		
																																				
public class AccountWebImpl extends AccountModel
implements ModelUpdateListener{
 private ModelManager mm;
 private Account acctEjb;
 public AccountWebImpl(ModelManager mm){
  super(null,null,null};
  this.mm=mm;
  mm.addListener(JNDINames.ACCOUNT_EJBHOME,this);
 }
 public void performUpdate(){
  if(acctEjb==null)  {
   acctEjb=mm.getAccountEJB();
  }
  try{
   if(acctEjb !=null)copy(acctEjb.getDetails());
  }catch(RemoteException re){
   throw new GeneralFailureException(re);
  }
 }
}
																																		
																																


控制

控制負(fù)責(zé)處理用戶請(qǐng)求、調(diào)用相應(yīng)的模型、更新模型的狀態(tài)、刷新視圖以及返回用戶合理的頁(yè)面。示例的所有控制對(duì)象如圖8所示。



圖8 控制對(duì)象圖

1.RequestProcessor

RequestProcessor接收并處理用戶的所有請(qǐng)求,調(diào)用RequestToEventTranslator對(duì)象把請(qǐng)求轉(zhuǎn)換成預(yù)定義的事件,在事件處理完成后,進(jìn)行視圖更新。 代碼如下所示:

																																		
																																				
public class RequestProcessor{
     private ShoppingClientControllerWebImpl scc;
     private ModelManager mm;
     private ModelUpdateNotifier mun;
     private RequestToEventTranslator eventTranslator;
     private SecurityAdapter securityAdapter;
     public void init(...)  {
      mm = (ModelManager)session.getAttribute("modelManager");
      mun = mm;
      SCC = new ShoppingClientControllerWebImpl(session);
      eventTranslator= new RequestToEventTranslator(this,mm);
     }
     public void processRequest(HttpServletRequest req){
      checkForWebServerLogin(req);
      EStoreEvent event = eventTranslator.processRequest(req);
      if (event != null){
       Collection updatedModelList = scc.handleEvent(event);
       mun.notifyListeners(updatedModelList);
      }     
     }
    }
																																		
																																


2.ShoppingClientControllerWebImpl

ShoppingClientContronerWebImpl是調(diào)用EJB層的ShoppingClientController代理對(duì)象,代碼如下所示:

																																		
																																				
public class ShoppingClientControllerWebImpl{
     private com....ejb.ShoppingClientController sccEjb;
     private HttpSession session;
     public ShoppingClientControllerWebImpl(HttpSession session){
      this.session = session;   
      ModelManager mm= (ModelManager)session.getAttribute("modelManager");
      sccEjb = mm.getSCCEJB();    
     }
     public synchronized AccountModel getAccount(){
      return sccEjb.getAccount().getDetails();
     }    
     ......   
     public synchronized Collection handleEvent(EStoreEvent ese){
      return sccEjb.handleEvent(ese);
     }
     public synchronized void remove()  {
      sccEjb.remove();
     }
    }
																																		
																																


3.ShoppingClientController

ShoppingClientController是有狀態(tài)的會(huì)話EJB,它為每個(gè)用戶建立一個(gè)單獨(dú)的實(shí)例,負(fù)責(zé)購(gòu)物車和賬號(hào)的生命周期,并負(fù)責(zé)處理事件。同時(shí)它也控制狀態(tài)機(jī)StateMachine的生命周期。代碼參見賽迪網(wǎng)http://linux.ccidnet.com的期刊瀏覽2003年第6期。

4.StateMachine

StateMachine實(shí)現(xiàn)核心的業(yè)務(wù)邏輯,它負(fù)責(zé)改變模型的狀態(tài),包括處理每個(gè)業(yè)務(wù)事件的方法。代碼參見賽迪網(wǎng)http://linux.ccidnet.com的期刊瀏覽2003年第6期。

  小結(jié)

  J2EE網(wǎng)站的開發(fā)方法,即是Internet的開發(fā)方法。Internet開發(fā)的發(fā)展可以劃分為三個(gè)階段:第一階段是將業(yè)務(wù)邏輯和表現(xiàn)邏輯完全集成在一起,采用HTML、JSP和Servlets技術(shù)開發(fā);第二階段是將業(yè)務(wù)邏輯和表現(xiàn)邏輯分開,采用HTML、JSP、Servlets、JavaBeans Compoments和Custom Tags技術(shù)開發(fā);第三個(gè)階段是MVC設(shè)計(jì)模式(J2EE的開發(fā)方法)。今天,MVC設(shè)計(jì)模式已成為Internet開發(fā)發(fā)展的主流。無(wú)論是通過第一階段開發(fā)的應(yīng)用,還是通過第二階段開發(fā)的應(yīng)用,都會(huì)面臨著開發(fā)人員的分工、應(yīng)用的可維護(hù)性和可擴(kuò)展性及可測(cè)量性的問題。為此,我們?cè)谠O(shè)計(jì)階段關(guān)心的重點(diǎn)是系統(tǒng)結(jié)構(gòu)的復(fù)雜程度、代碼之間的耦合度、代碼的易維護(hù)性、應(yīng)用框架的可重用性、EJB組件的可重用性和易測(cè)試性,以及不同技能開發(fā)人員的分工等。用縱觀全局的眼光來(lái)看,在Internet系統(tǒng)開始設(shè)計(jì)的時(shí)候,就要考慮開發(fā)、運(yùn)行、維護(hù)階段的問題