日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

基于 Dojo toolkit 實(shí)現(xiàn) web2.0 的 MVC 模式

 gyb98 2010-12-30

基于 Dojo toolkit 實(shí)現(xiàn) web2.0 的 MVC 模式

王 為民, 軟件工程師, EMC
孫 曼, 軟件工程師, EMC
章 巖, 軟件工程師, EMC

簡(jiǎn)介: 本文從介紹傳統(tǒng)的 MVC 模式入手,分析了 WEB2.0 模式下的 MVC 模式與傳統(tǒng) MVC 模式的區(qū)別與利弊,同時(shí)用 DOJO 構(gòu)造了一個(gè) WEB2.0 模式下的 MVC 實(shí)例,方便讀者理解,在此基礎(chǔ)上,介紹了 DOJO 實(shí)現(xiàn) WEB2.0 的 MVC 模式的高級(jí)特性,實(shí)現(xiàn)動(dòng)態(tài)刷新。

發(fā)布日期: 2009 年 12 月 17 日 
級(jí)別: 初級(jí) 
訪問(wèn)情況 476 次瀏覽 
建議: 0 (添加評(píng)論)

 平均分 (共 2 個(gè)評(píng)分 )

前言

MVC 模式是設(shè)計(jì)模式中的經(jīng)典模式,它可以有效的分離數(shù)據(jù)層,展示層,和業(yè)務(wù)邏輯層。Web2.0 技術(shù)由于其良好的用戶體驗(yàn)被廣泛應(yīng)用于 WEB 應(yīng)用的展示層。但是在傳統(tǒng)的 web 開(kāi)發(fā)中,展示層的和業(yè)務(wù)邏輯層代碼大量耦合,使得應(yīng)用的可擴(kuò)展性嚴(yán)重降低,同時(shí)頁(yè)面層代碼的可復(fù)用性也很低。本文用實(shí)例介紹,如何使用 dojo toolkit 擴(kuò)展 dojo 的頁(yè)面控件并實(shí)現(xiàn) MVC 模式,有效的分離了展示層與業(yè)務(wù)邏輯層的代碼,同時(shí)使得展示層代碼可復(fù)用性大大提高。

第一部分:Dojo 構(gòu)造 MVC 與傳統(tǒng) MVC 模式的區(qū)別

傳統(tǒng)的 MVC 模式

MVC 模式是"Model-View-Controller"的縮寫(xiě),中文翻譯為"模式 - 視圖 - 控制器"。 基于 MVC 模式的程式一般都是由 Controller, View, Model 這三個(gè)部分組成。Controller 在應(yīng)用程式中主要接受用戶觸發(fā)的事件 (Event),然后 Controller 根據(jù)事先定義好的業(yè)務(wù)邏輯去更新 Model. 在 Model 更新之后,Model 會(huì)通知 (notify) 已注冊(cè)到該模型的視圖(view)進(jìn)行刷新 (refresh) 操作,最后程式將刷新后的視圖展示給用戶。

Model 的差別:

傳統(tǒng)的 MVC 模式的 model 是一個(gè) javabean,如清單三。而在 DOJO 構(gòu)造的 MVC 當(dāng)中,model 是一個(gè) json 的數(shù)據(jù)結(jié)構(gòu),封裝完,返回的數(shù)據(jù)結(jié)構(gòu)形式如下:

 {“books”:[{“bookName:The art of programming”,”price:90”},
                  {“bookName:MVC introduction”,”price:90”}]} 

數(shù)據(jù)流向的不同:

在傳統(tǒng)的 MVC 模式中,數(shù)據(jù)的獲得過(guò)程如下:

JSP — >Servlet — >Service — >DAO — >JavaBean — > 數(shù)據(jù)庫(kù)

或者

JSP — >Servlet — > DAO — >JavaBean — > 數(shù)據(jù)庫(kù)

而在 web2.0 的 MVC 模式中,數(shù)據(jù)的傳輸途徑如下:

JSP — >Javascript — >Servlet — >Service — >DAO — >JavaBean — > 數(shù)據(jù)庫(kù)

或者

JSP — >Javascript — >Servlet — > DAO — >JavaBean — > 數(shù)據(jù)庫(kù)

比如在 DOJO 中,用戶在 JSP 頁(yè)面發(fā)出數(shù)據(jù)請(qǐng)求后,會(huì)先提交給 DOJO 的 Widget 的 Javascript 函數(shù)做處理,這個(gè) widget 調(diào)用相應(yīng)的 servlet,由 servlet 將取到的數(shù)據(jù)轉(zhuǎn)換成 javascript 能夠識(shí)別的 Json 數(shù)據(jù)結(jié)構(gòu),然后這個(gè) widget 根據(jù)自己的刷新規(guī)則,將數(shù)據(jù)填入 widget 的 html template 中,顯示給用戶。

Servlet 控制層的差別

正是因?yàn)閿?shù)據(jù)流向的區(qū)別,導(dǎo)致了傳統(tǒng)的 MVC 的控制層與 web2.0 的控制層有了很大區(qū)別,如果說(shuō)傳統(tǒng) MVC 的控制層是 servlet 的話,那么在 web2.0 中,這個(gè)控制的角色已經(jīng)開(kāi)始由 servlet 轉(zhuǎn)移到了 javascript 中。

在傳統(tǒng)的 MVC 模式中,servlet 負(fù)責(zé)取數(shù)據(jù)和封裝數(shù)據(jù),有時(shí)候也會(huì)包括一些刷新頁(yè)面數(shù)據(jù)的代碼段,而 jsp 負(fù)責(zé)解析數(shù)據(jù),填充數(shù)據(jù)和顯示數(shù)據(jù)??紤]到 JSP 從廣義上來(lái)說(shuō)也是一個(gè) servlet,所以 servlet 就包含了從取數(shù)據(jù)、封裝數(shù)據(jù)、解析數(shù)據(jù)、填充數(shù)據(jù)和顯示數(shù)據(jù)的一條龍服務(wù)。

而在 web2.0 中,servlet 仍然負(fù)責(zé)取數(shù)據(jù)和封裝數(shù)據(jù),但是解析數(shù)據(jù)、填充數(shù)據(jù)和顯示數(shù)據(jù)已經(jīng)不再由 JSP 來(lái)完成,解析數(shù)據(jù)和填充數(shù)據(jù)都是在 javascript 中完成。在 dojo 中負(fù)責(zé)解析數(shù)據(jù)和填充數(shù)據(jù)的就是 widget。那么什么是 dojo 的 widget 呢?

什么是 dojo 的 widget ?

Dojo 的 widget 由三部分構(gòu)成,即:

數(shù)據(jù)控制層,一般是 javascript 編寫(xiě)的一個(gè)對(duì)象,它是 dojo widget 的核心,解析數(shù)據(jù)和填充數(shù)據(jù)都是在這里面完成,同時(shí)還可以包含與這個(gè) widget 相關(guān)的一些功能函數(shù),比如隱藏這個(gè) widget,刪除這個(gè) widget 等等。

數(shù)據(jù)顯示層,一般是由 HTML 編寫(xiě)的模板文件,它提供基本的 Widget HTML 視圖。

Css 樣式文件,定義標(biāo)簽的樣式,在 js 代碼或者 HTML 模板文件中使用。

View 顯示層的差別

從上面的 dojo widget 的定義可以看出,傳統(tǒng)的 MVC 與 web2.0 也是有很大區(qū)別的,比如在 dojo 中,view 不在是一個(gè) jsp 頁(yè)面,而是由 dojo widget 定義的 template,既由 html 代碼編寫(xiě)的特殊模板。

Dojo 的 widget 由三部分構(gòu)成,即:

數(shù)據(jù)控制層,一個(gè)是 javascript 編寫(xiě)的一個(gè)對(duì)象,它是 dojo widget 的核心,解析數(shù)據(jù)和填充數(shù)據(jù)都是在這里面完成,同時(shí)還可以包含與這個(gè) widget 相關(guān)的一些功能函數(shù),比如隱藏這個(gè) widget,刪除這個(gè) widget 等等。

頁(yè)面顯示層(template),是由 HTML 編寫(xiě)的模板文件,它提供基本的 Widget HTML 視圖。

CSS 樣式文件,定義標(biāo)簽的樣式,在 js 代碼或者 HTML 模板文件中使用。

第二部分 抽象 dojo widget 的共性,實(shí)現(xiàn)可復(fù)用的 MVC

在上一章中,我們列舉了一個(gè) dojo 的 widget 特性,那么我們是否可以對(duì) widget 在進(jìn)一步的提取出共性,提高 widget 的可復(fù)用性,答案是肯定的。


圖 1. dojo 實(shí)現(xiàn) mvc
 

使用 dojo 實(shí)現(xiàn) mvc

使用 widget 作為展示層的,可以很好的將頁(yè)面元素很好的封裝和重用。但是在 web 應(yīng)用開(kāi)發(fā)中頁(yè)面展示層往往需要和服務(wù)器端的數(shù)據(jù)進(jìn)行交互,在 web2.0 技術(shù)的支援下,我們可以使用 ajax 將頁(yè)面元素的改變反應(yīng)的服務(wù)器端進(jìn)行處理,然后將返回結(jié)果通過(guò)在頁(yè)面中預(yù)先定義的回調(diào)函數(shù)進(jìn)行性展示。然后大量的回調(diào)函數(shù)將會(huì)破壞展示層的良好的封裝。使得代碼晦澀難懂。因此我們需要在 web2.0 應(yīng)用中實(shí)現(xiàn) MVC 模式,將模型改變,以及視圖的自動(dòng)刷新進(jìn)行封裝,已取得更好的復(fù)用性。


清單 11. VIEW.js
				
 if (!dojo._hasResource["taas._base.View"]) { 
  dojo._hasResource["taas._base.View"] = true; 
  dojo.require("dijit._Widget"); 
  dojo.require("dijit._Templated"); 
  dojo.provide("taas._base.View"); 
  dojo.declare("taas._base.View",null,{ 
    _model:null, 
    _taasSrcPath:dojo.moduleUrl("taas",""), 
    responseObject:null, 
    refresh:function(object){ 
      this.responseObject = object;    
      if(this.updateView!=undefined&&typeof this.updateView=="function"){ 
        this.updateView(this.responseObject); 
      } 
    }, 
    _bindModel:function(dataModel){ 
      this._model = dataModel;    
    } 
  }); 
 } 

清單中的程序 定義了抽象的 view. 其中 _model 為為抽象 view 所關(guān)聯(lián)的數(shù)據(jù)模型。

bindModel 方法將視圖與數(shù)據(jù)模型進(jìn)行關(guān)聯(lián)。Refresh 方法提供當(dāng)模型改變時(shí),模型可以調(diào)用的用于刷新視圖的方法。在 Refresh 函數(shù)中判斷是否存在 updateView 函數(shù)如果存在就調(diào)用該函數(shù)。updateView 函數(shù)用于用于自定義的視圖如何進(jìn)行刷新。


清單 12. MODEL.js
				
 if (!dojo._hasResource["taas._base.DataModel"]) { 
  dojo._hasResource["taas._base.DataModel"] = true; 
  dojo.provide("taas._base.DataModel"); 
  dojo.declare("taas._base.DataModel",null,{ 
    _views:null, 
    uri:null, 
    constructor : function(uri){ 
      this._views = new Array(); 
      this.uri = uri; 
    }, 
    registerView:function(view){      
      view.bindModel(this); 
      this._views.push(view); 
    }, 
    unRegisterView : function (view){ 
      var i = this._views.indexOf(view); 
          if(i > 0) 
              this._views.slice(i,1); 
    }, 
    notifyViews : function (json){ 
      for(var i = 0; i < this._views.length; i++) 
          { 
        this._views[i].refresh(json); 
          } 
    } 
  }); 
 } 

清單中代碼為抽象的 model. 它使用了 registerView,unRegisterView notifyViews 來(lái)進(jìn)行與視圖的通信。registerView 函數(shù)可以讓 model 綁定一個(gè)視圖,unRegisterView 函數(shù)可以讓 model 解綁定一個(gè)視圖,notifyViews 函數(shù),用于通知該模型所綁定的所有視圖進(jìn)行刷新。


清單 13. Controller.js
				
 if (!dojo._hasResource["taas._base.Controller2"]) { 
  dojo._hasResource["taas._base.Controller2"] = true;  
  dojo.provide("taas._base.Controller2"); 
  dojo.declare("taas._base.Controller2",null,{  
  }); 
  taas._base.Controller2.remoteUpdate = function (dataModelUri,topic,formId){ 
   dojo.info("taas._base.Controller2 deprecated, use taas._base.Controller instead, 1.0") 
    _topic = topic; 
    _dataModelUri = dataModelUri; 
    _formId = formId; 
    _form = dojo.byId(_formId); 
    var doResponse = function (responseText){    
      dojo.publish(_topic,[responseText]);        
    }; 
    dojo.xhrGet({ 
        url: _dataModelUri, 
        preventCache: true, 
        form:_form, 
        handleAs: "text", 
        method:"get", 
        load: doResponse 
    }); 
  } 
 } 

清單中的代碼為 Controller 類(lèi),主要負(fù)責(zé)與服務(wù)器端的 servlet 通信。獲取服務(wù)器端的數(shù)據(jù)更新,并將更新后的數(shù)據(jù)通知到頁(yè)面模型層。

使 widget 繼承 view. 很簡(jiǎn)單,只需要在 declare 中申明該 widget 繼承與 view 就可以了。


清單 15. updateView.
				
 taas.layout.LinkPane.prototype.updateView = function(json) { 
	 alert(“this view has been updated”); 	
 } 

清單中的代碼實(shí)現(xiàn)了自定義的視圖刷新規(guī)則 updateView,該函數(shù)被動(dòng)態(tài)綁定到 LinkPane widget 對(duì)象中。


清單 16. ProjectList 模型 .
				
 function ProjectList(uri) { 
	 this.uri = uri; 
 } 
ProjectList.prototype = new taas._base.DataModel(this.uri); 
Var projectListModel = new ProjectList(“http://localhost:8080/servlet/ProjectManagement”) 

清單中的代碼從 DataModel 抽象對(duì)象中派生出 ProjectList 對(duì)象模型以供 LinkPane 使用。


清單 17. 模型與視圖綁定 .
				
 var  myLinkPane = new taas.layout.LinkPane({},”linkpane01”). 
 projectListModel.registerView(myLinkPane); 


清單 18. controller 與遠(yuǎn)程 servlet 通信 .
				
 <input type="button"
  onclick="taas._base.Controller.remoteUpdate(ProjectListModel,
  { 'action' : 'listall' })"> 
 </input> 

清單中代碼假設(shè)我們?cè)陧?yè)面中使用了一個(gè) button,button 的 onclick 事件調(diào)用 controller 的 remoteUpdate 方法與 Model 中對(duì)應(yīng)的 servlet 通訊。

圖 2 程序執(zhí)行過(guò)程。Sequence 圖。

第三部分 使用 dojo 的 subscribe 和 publish 方式簡(jiǎn)化代碼

由于 dojo1.2 版本已經(jīng)提供 subscribe/publish 消息通知機(jī)制,所以可以將 model 與 view 的關(guān)系使用 subscribe/publish 機(jī)制來(lái)簡(jiǎn)化。簡(jiǎn)化后 model 被 subscribe/publish 機(jī)制中的 topic 代替 .

下面為簡(jiǎn)化后的代碼。


清單 19. 修改后的 VIEW.js
				
 if (!dojo._hasResource["taas._base.View"]) { 
  dojo._hasResource["taas._base.View"] = true; 
  dojo.require("dijit._Widget"); 
  dojo.require("dijit._Templated"); 
  dojo.provide("taas._base.View"); 
  dojo.declare("taas._base.View",null,{ 
    _model:null, 
    topic:"", 
    _taasSrcPath:dojo.moduleUrl("taas",""), 
    responseObject:null, 
    refresh:function(object){ 
      this.responseObject = object;    
      if(this.updateView!=undefined&&typeof this.updateView=="function"){ 
        this.updateView(this.responseObject); 
      } 
    }, 
    bindModel:function(dataModel){ 
      this._model = dataModel;      
    }, 
    _bindTopic:function(){      
      if(this.topic!=undefined&&this.topic!=""){ 
        dojo.subscribe(this.topic,this,"refresh"); 
      } 
    } 
  }); 
 } 


清單 21. 修改后的 Controller.js
				
 if (!dojo._hasResource["taas._base.Controller"]) { 
  dojo._hasResource["taas._base.Controller"] = true; 
  dojo.provide("taas._base.Controller"); 
  dojo.declare("taas._base.Controller",null,{ 
  }); 
  taas._base.Controller.remoteUpdate = function (dataModelUri,topic,requestContent){ 
    _topic = topic; 
    _dataModelUri = dataModelUri; 
    _requestContent = requestContent; 
    console.debug(_requestContent); 
    var doResponse = function (responseText){ 
      dojo.forEach(_topic,function(item){ 
        var jsonObj = dojo.fromJson(responseText)[item]; 
        //console.debug(dojo.toJson(jsonObj)); 
        dojo.publish(item,[dojo.toJson(jsonObj)]);  
      });    
    }; 
    var getFormJson = function() {      
      dojo.xhrGet({ 
        url: _dataModelUri, 
        preventCache: true, 
        content:_requestContent, 
        handleAs: "text", 
        method:"get", 
        load: doResponse 
      }); 
    }; 
    var getFromForm = function() { 
      dojo.xhrGet({ 
        url: _dataModelUri, 
        preventCache: true, 
        form:_requestContent, 
        handleAs: "text", 
        method:"get", 
        load: doResponse 
      }); 
    };    
    var doRequest = function () {    
      if(dojo.isObject(_requestContent)) { 
        getFormJson(); 
      } 
      else if(dojo.isString(_requestContent)){ 
        getFromForm(); 
      } 
    };    
    doRequest();    
  }  
 } 

如何使用

 <input type="button" 
 onclick='taas._base.Controller.remoteUpdate ( 
 'http://localhost:8080/servlet/ProjectManagement ' , ["projects"], { 
        'action' : 'querybyuserid'
      });”

清單中代碼中 onclick 屬性調(diào)用了 Controller 的 remoteUpdate 方法,該方法將調(diào)用遠(yuǎn)程 servlet 的 doGet/doPost 方法,并將相應(yīng)的請(qǐng)求參數(shù)發(fā)給遠(yuǎn)程 servlet。遠(yuǎn)程 servlet 收到請(qǐng)求后進(jìn)行相應(yīng)的業(yè)務(wù)邏輯處理,最后將處理結(jié)果返回到 controller 的回調(diào)函數(shù)執(zhí)行從而刷新視圖。

結(jié)束語(yǔ)

使用 web2.0 的 MVC 模式,使我們能更加關(guān)于與業(yè)務(wù)邏輯的實(shí)現(xiàn),而不用糾纏與服務(wù)器端數(shù)據(jù)模型與 web 頁(yè)面的展示如何同步。


參考資料

作者簡(jiǎn)介

王為民,現(xiàn)為 IBM 中國(guó)開(kāi)發(fā)中心軟件工程師,主要關(guān)注領(lǐng)域云計(jì)算、OSGI、人工智能。

孫曼,IBM CDL 高級(jí)軟件工程師 , 主要關(guān)注領(lǐng)域云計(jì)算。

章巖,IBM 軟件工程師,在 IBM CDL TaaS(Test as a Service) 部門(mén)從事軟件自動(dòng)化測(cè)試開(kāi)發(fā)工作。主要關(guān)注領(lǐng)域軟件測(cè)試自動(dòng)化和云計(jì)算。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多