基于 Dojo toolkit 实现 web2.0 的 MVC 模式

前言

MVC 模式是设计模式中的经典模式,它可以有效的分离数据层,展示层,和业务逻辑层。Web2.0 技术由于其良好的用户体验被广泛应用于 WEB 应用的展示层。但是在传统的 web 开发中,展示层的和业务逻辑层代码大量耦合,使得应用的可扩展性严重降低,同时页面层代码的可复用性也很低。本文用实例介绍,如何使用 dojo toolkit 扩展 dojo 的页面控件并实现 MVC 模式,有效的分离了展示层与业务逻辑层的代码,同时使得展示层代码可复用性大大提高。

第一部分:Dojo 构造 MVC 与传统 MVC 模式的区别

传统的 MVC 模式

MVC 模式是"Model-View-Controller"的缩写,中文翻译为"模式 - 视图 - 控制器"。 基于 MVC 模式的程式一般都是由 Controller, View, Model 这三个部分组成。Controller 在应用程式中主要接受用户触发的事件 (Event),然后 Controller 根据事先定义好的业务逻辑去更新 Model. 在 Model 更新之后,Model 会通知 (notify) 已注册到该模型的视图(view)进行刷新 (refresh) 操作,最后程式将刷新后的视图展示给用户。

Model 的差别:

传统的 MVC 模式的 model 是一个 javabean,如清单三。而在 DOJO 构造的 MVC 当中,model 是一个 json 的数据结构,封装完,返回的数据结构形式如下:


1

2

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

                 {“bookName:MVC introduction”,”price:90”}]}

数据流向的不同:

在传统的 MVC 模式中,数据的获得过程如下:

JSP — >Servlet — >Service — >DAO — >JavaBean — > 数据库

或者

JSP — >Servlet — > DAO — >JavaBean — > 数据库

而在 web2.0 的 MVC 模式中,数据的传输途径如下:

JSP — >Javascript — >Servlet — >Service — >DAO — >JavaBean — > 数据库

或者

JSP — >Javascript — >Servlet — > DAO — >JavaBean — > 数据库

比如在 DOJO 中,用户在 JSP 页面发出数据请求后,会先提交给 DOJO 的 Widget 的 Javascript 函数做处理,这个 widget 调用相应的 servlet,由 servlet 将取到的数据转换成 javascript 能够识别的 Json 数据结构,然后这个 widget 根据自己的刷新规则,将数据填入 widget 的 html template 中,显示给用户。

Servlet 控制层的差别

正是因为数据流向的区别,导致了传统的 MVC 的控制层与 web2.0 的控制层有了很大区别,如果说传统 MVC 的控制层是 servlet 的话,那么在 web2.0 中,这个控制的角色已经开始由 servlet 转移到了 javascript 中。

在传统的 MVC 模式中,servlet 负责取数据和封装数据,有时候也会包括一些刷新页面数据的代码段,而 jsp 负责解析数据,填充数据和显示数据。考虑到 JSP 从广义上来说也是一个 servlet,所以 servlet 就包含了从取数据、封装数据、解析数据、填充数据和显示数据的一条龙服务。

而在 web2.0 中,servlet 仍然负责取数据和封装数据,但是解析数据、填充数据和显示数据已经不再由 JSP 来完成,解析数据和填充数据都是在 javascript 中完成。在 dojo 中负责解析数据和填充数据的就是 widget。那么什么是 dojo 的 widget 呢?

什么是 dojo 的 widget ?

Dojo 的 widget 由三部分构成,即:

数据控制层,一般是 javascript 编写的一个对象,它是 dojo widget 的核心,解析数据和填充数据都是在这里面完成,同时还可以包含与这个 widget 相关的一些功能函数,比如隐藏这个 widget,删除这个 widget 等等。

数据显示层,一般是由 HTML 编写的模板文件,它提供基本的 Widget HTML 视图。

Css 样式文件,定义标签的样式,在 js 代码或者 HTML 模板文件中使用。

View 显示层的差别

从上面的 dojo widget 的定义可以看出,传统的 MVC 与 web2.0 也是有很大区别的,比如在 dojo 中,view 不在是一个 jsp 页面,而是由 dojo widget 定义的 template,既由 html 代码编写的特殊模板。

Dojo 的 widget 由三部分构成,即:

数据控制层,一个是 javascript 编写的一个对象,它是 dojo widget 的核心,解析数据和填充数据都是在这里面完成,同时还可以包含与这个 widget 相关的一些功能函数,比如隐藏这个 widget,删除这个 widget 等等。

页面显示层(template),是由 HTML 编写的模板文件,它提供基本的 Widget HTML 视图。

CSS 样式文件,定义标签的样式,在 js 代码或者 HTML 模板文件中使用。

第二部分 抽象 dojo widget 的共性,实现可复用的 MVC

在上一章中,我们列举了一个 dojo 的 widget 特性,那么我们是否可以对 widget 在进一步的提取出共性,提高 widget 的可复用性,答案是肯定的。

图 1. dojo 实现 mvc

使用 dojo 实现 mvc

使用 widget 作为展示层的,可以很好的将页面元素很好的封装和重用。但是在 web 应用开发中页面展示层往往需要和服务器端的数据进行交互,在 web2.0 技术的支援下,我们可以使用 ajax 将页面元素的改变反应的服务器端进行处理,然后将返回结果通过在页面中预先定义的回调函数进行性展示。然后大量的回调函数将会破坏展示层的良好的封装。使得代码晦涩难懂。因此我们需要在 web2.0 应用中实现 MVC 模式,将模型改变,以及视图的自动刷新进行封装,已取得更好的复用性。

清单 11. VIEW.js

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

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 所关联的数据模型。

bindModel 方法将视图与数据模型进行关联。Refresh 方法提供当模型改变时,模型可以调用的用于刷新视图的方法。在 Refresh 函数中判断是否存在 updateView 函数如果存在就调用该函数。updateView 函数用于用于自定义的视图如何进行刷新。

清单 12. MODEL.js

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

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 来进行与视图的通信。registerView 函数可以让 model 绑定一个视图,unRegisterView 函数可以让 model 解绑定一个视图,notifyViews 函数,用于通知该模型所绑定的所有视图进行刷新。

清单 13. Controller.js

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

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 类,主要负责与服务器端的 servlet 通信。获取服务器端的数据更新,并将更新后的数据通知到页面模型层。

使 widget 继承 view. 很简单,只需要在 declare 中申明该 widget 继承与 view 就可以了。

清单 15. updateView.

1

2

3

taas.layout.LinkPane.prototype.updateView = function(json) {

    alert(“this view has been updated”);  

}

清单中的代码实现了自定义的视图刷新规则 updateView,该函数被动态绑定到 LinkPane widget 对象中。

清单 16. ProjectList 模型 .

1

2

3

4

5

function ProjectList(uri) {

     this.uri = uri;

 }

ProjectList.prototype = new taas._base.DataModel(this.uri);

Var projectListModel = new ProjectList(“http://localhost:8080/servlet/ProjectManagement”)

清单中的代码从 DataModel 抽象对象中派生出 ProjectList 对象模型以供 LinkPane 使用。

清单 17. 模型与视图绑定 .

1

2

var  myLinkPane = new taas.layout.LinkPane({},”linkpane01”).

projectListModel.registerView(myLinkPane);

清单 18. controller 与远程 servlet 通信 .

1

2

3

4

<input type="button"

 onclick="taas._base.Controller.remoteUpdate(ProjectListModel,

 { ‘action‘ : ‘listall‘ })">

</input>

清单中代码假设我们在页面中使用了一个 button,button 的 onclick 事件调用 controller 的 remoteUpdate 方法与 Model 中对应的 servlet 通讯。

图 2 程序执行过程。Sequence 图。

第三部分 使用 dojo 的 subscribe 和 publish 方式简化代码

由于 dojo1.2 版本已经提供 subscribe/publish 消息通知机制,所以可以将 model 与 view 的关系使用 subscribe/publish 机制来简化。简化后 model 被 subscribe/publish 机制中的 topic 代替 .

下面为简化后的代码。

清单 19. 修改后的 VIEW.js

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

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

 

}

如何使用


1

2

3

4

5

<input type="button"

onclick=‘taas._base.Controller.remoteUpdate (

‘http://localhost:8080/servlet/ProjectManagement ‘ , ["projects"], {

       ‘action‘ : ‘querybyuserid‘

     });”

清单中代码中 onclick 属性调用了 Controller 的 remoteUpdate 方法,该方法将调用远程 servlet 的 doGet/doPost 方法,并将相应的请求参数发给远程 servlet。远程 servlet 收到请求后进行相应的业务逻辑处理,最后将处理结果返回到 controller 的回调函数执行从而刷新视图。

结束语

使用 web2.0 的 MVC 模式,使我们能更加关于与业务逻辑的实现,而不用纠缠与服务器端数据模型与 web 页面的展示如何同步。

相关主题

时间: 2024-11-10 13:10:07

基于 Dojo toolkit 实现 web2.0 的 MVC 模式的相关文章

【Unity】基于MVC模式的背包系统 UGUI实现

本文基于MVC模式,用UGUI初步实现了背包系统. 包含点击和拖拽两种逻辑,先献上源代码,工程和分析稍后补充. Model 层 using UnityEngine; using UnityEngine.UI; using System.Collections; using System.Collections.Generic; /// <summary> /// 脚本功能:MVC模式--Model层,定义物品结构,保存物品数据 /// 添加对象:Bag 背包(Canvas下的空对象) ///

基于mvc模式的应用框架之struts

Struts就是基于mvc模式的框架! (struts其实也是servlet封装,提高开发效率!) Struts开发步骤: 1. web项目,引入struts - jar包 2. web.xml中,引入struts的核心功能 配置过滤器 3. 开发action 4. 配置action src/struts.xml 1. 引入8个jar文件 2. web.xml <!-- 引入struts核心过滤器 --> <filter> <filter-name>struts2<

【Web】Web1.0和Web2.0

具体请参照百度百科: web1.0时代是一个群雄并起,逐鹿网络的时代,虽然各个网站采用的手段和方法不同,但第一代互联网有诸多共同的特征,表现在技术创新主导模式.基于点击流量的盈利共通点.门户合流.明晰的主营兼营产业结构.动态网站.在WEB1.0上做出巨大贡献的公司有Netscape,Yahoo和Google. Netscape研发出第一个大规模商用的浏览器,Yahoo的杨致远提出了互联网黄页, 而Google后来居上,推出了大受欢迎的搜索服务. 中文名 web1.0 特    点 群雄并起,逐鹿

Web1.0、Web2.0、Web3.0的主要区别

Web1.0:以静态.单向阅读为主,网站内信息可以直接和其他网站信息进行交互,能通过第三方信息平台同时对多家网站信息进行整合使用. Web2.0:以分享为特征的实时网络,用户在互联网上拥有自己的数据,并能在不同的网站上使用. Web3.0:将以网络化和个性化为特征,提供更多人工智能服务,完全基于Web,用浏览器即可实现复杂的系统程序才具有的功能. Web3.0的特征分析: 1.微内容(Widget)的自由整合与有效聚合 2.适合多种终端平台,实现信息服务的普适性 3.良好的人性化用户体验,以及基

SNF快速开发平台3.0之--MVC 打印解决方案

SNF-MVC打印报表方案: 报表模块创建的过程如下: 利用Stimulsoft Reports客户端报表工具新增一个报表文件 *.mrt 当然你也可以拿好用的*.mrt模版文件进行复制出来一个,我常用这个方法. 按规定要求放于指定位置:Areas->Sys->Reports->BaseRole.mrt 打开对应的页面功能,点击打印即可,也可以在线编辑报表 第一步:配置打印按钮 第二步:配置打印方法 //打印 this.printClick = function () { snf.ope

百科知识 什么是Web2.0

web2.0 百科名片 Web2.0 是相对Web1.0 的新的一类互联网应用的统称.Web1.0 的主要特点在于用户通过浏览器获取信息.Web2.0 则更注重用户的交互作用,用户既是网站内容的浏览者,也是网站内容的制造者.所谓网站内容的制造者是说互联网上的每一个用户不再仅仅是互联网的读者,同时也成为互联网的作者:不再仅仅是在互联网上冲浪,同时也成为波浪制造者;在模式上由单纯的"读"向"写"以及"共同建设"发展:由被动地接收互联网信息向主动创造互

MVC模式下基于SSH三大框架的java web项目excel表格的导出(不依赖另外的jar包)

最近工作中碰到了需要将web页面的表格内容导出到excel表格并下载到本地的需求.以下是在利用网上资源.与同事探讨下,完成的代码. 首先我们需要有定义好的实体类.以下是截取了项目中用到的部分代码. 1 public class QyggDocuments implements java.io.Serializable { 2 3 private static final long serialVersionUID = -2543382529255041149L; 4 5 private Stri

Web2.0简单介绍和软件开发结构浅谈

1.Web2.0指的是利用Web的平台,由用户主导而生成内容的互联网产品模式,为了区别由网站雇员主导生成内容的传统网站而定义为Web2.0基于Web2.0这些特点所产生的具有代表性的服务如下:博客.内容源.WiKi.参与评论与评分的Digg机制.美味书签.社会化网络.微博.基于位置信息的服务.即时通讯2.软件开发C/S结构与B/S结构的区别C/S结构大家都熟悉,即Clint/Server(客户端/服务器)结构,它通过将任务合理地分配到Clint端和Server端,来降低系统的通讯开销,不过需要安

基于 ASP.NET Core 2.0 WebAPI 后台框架搭建(0) - 目录概述

概述 博主自毕业后,进公司就一直是以ASP.NET MVC 5.0 + MySQL 进行项目开发,在项目也使用了很多常用功能,如 WCF.SignalR.微信公众号API.支付宝API.Dapper等等,前端是大杂烩,如:Bootstrap.AmazeUI.EasyUI.Light7.WeUI等等.其实对于我们公司的项目来说,技术栈虽说不庞大,但五脏俱全,而且基于这一套技术,开发速度有保证.但是,作为一个有梦想的程序猿,必须与时俱进,因此无意中接触了.Net Core 2.0.听说它是开源的?它