posts - 176, comments - 240, trackbacks - 0, articles - 7

PageFlow: Managed Navigation

Posted on 2006-11-05 20:35 canonical 阅读(2287) 评论(7)  编辑  收藏 所属分类: Witrix开发平台
  按照Tim Berners-Lee的原始设想,互联网的核心概念是超链接(hyperlink), 每一个可访问的资源都具有自己的URI(Universal Resource Identifier), 我们通过唯一的url可以访问到这些资源。从概念上说,每一个页面可以由一个两元组[title, url]来进行描述,title是url显示在界面上时的可读表述。在这一描述下,我们可以建立基本的页面浏览模型,包括浏览历史模型:我们可以把浏览过的页面保存在浏览历史列表中,通过选择历史列表中的条目实现页面跳转。但是随着网页的动态性不断增加,页面的资源语义逐渐丧失,url所对应的不再是一种静态的资源表述概念,而逐渐演变成为一种动态的访问函数. 例如
  /view.jsp?objectName=MyObj&objectEvent=ViewDetail&id=1
  一个url模式所对应的网页个数在理论上可能是无限多的. 从单一数据值到函数是系统复杂性本质上的一种飞跃. 为了不致在这种无限的世界中迷失方向,我们显然需要对于浏览过程进行更加有效的组织,建立更加有约束性的导航模型. 一种常见的导航模式是在页面的上方显示一条线性的导航路径, 与浏览历史模型不同的是, 页面转换时不是
  list > view item 1 ==>  list > view item 1 > view item 2
而是
   list > view item1 ==> list > view item2
  为了支持导航路径, 最简单的方式是将页面模型扩展为三元组[id, title, urlExpr], 其中urlExpr是动态表达式, 而id是固定的值. 例如 id=view, urlExpr=/view.jsp?objectName=MyObj&objectEvent=ViewDetail&id=${id}
  导航路径的变化规则为navHistory.removeAfter(newPage.id).add(newPage)
  为了进一步约化导航路径, 可以将页面模型扩展为
  [id, title, urlExpr, group, before, beforeGroup],
  其中group定义了页面的分组, 同组的页面在导航路径中相互替代, 而before和beforeGroup定义了页面在导航路径中的相对顺序. 例如对于
  [id='list' beforeGroup="detail"] [id='view' group='detail'] [id='update' group='detail']
在页面转换时, 导航路径变化不是
  list > view item1 ==> list > view item1 > update item1
而是
  list > view item1 ==> list > update item1
  在以上的页面模型中, 每一个id对应的是一个不同的页面模板(页面布局), 但是有时我们也需要在同一个页面布局中浏览无限分级的栏目, 此时可以将页面模型扩展为
  [id, title, urlExpr, group, before, beforeGroup, path]
 
  将以上的导航模型应用于一般的web应用时还需要克服一个小小的困难: 动态url的副作用. 例如/update.do?id=1&value=2这种具有动作语义的url访问直接破坏了页面的浏览模型,例如现在我们不再能够按F5键刷新页面,不能通过window.location=window.location调用来刷新页面,在页面回退时我们也将遇到种种困难。为了防止重复提交,一种常见的设计模式是分离POST和GET方法,即通过Form POST向上提交数据,处理完毕后通过redirect指令通知浏览器再次发起GET方法得到新的页面.具体做法如下  
    /redirect_after_action.do?id=1&value=2
  在执行完action之后, 服务器调用response.sendRedirect(get_url), 通知前台浏览器使用新的url重新取回页面. 这样最终我们可以确保所有页面都是可以通过url直接访问的(没有隐含的post参数),而且是可以重复访问的(无副作用因而可以反复刷新)!
  另一种方式是使用ajax方式提交更新请求,当ajax访问成功后, 在回调函数中进行页面跳转.例如:
  new js.Ajax().setObjectName('Test')
      .setObjectEvent('Update').addForm(myForm)
      .callRemote(function(returnValue){
        window.location = '/view.jsp?id=1';
      })  
这里我们也可以根据returnValue的不同选择跳转到不同页面.
  在Witrix平台中, 基于Jsplet框架我们定义了PageFlow对象, 它将可配置的导航模型引入到任意页面的组织过程中. 在跳转到一个新的页面的时候, 访问url如下:
  /pageflow.jsp?objectName=MyNav&objectEvent=NavToPage&_pageId=view&id=3
在重新访问历史页面的时候,只需要
 /pageflow.jsp?objectName=MyNav&objectEvent=NavToHistoryPage&_pageId=view
  基于jsplet框架的对象化特性,MyNav对象在session中保持了flow的所有状态变量,不需要任何框架上特殊的支持。我们可以在任意页面跳出pageflow, 并在任何时刻选择跳回pageflow, 这些动作不会影响到flow对象的状态。而通过objectScope的设置我们可以精细的控制flow对象的生命周期。同时基于对象化设置,访问页面时我们只需要资源的相对名称(relative identifier), 例如对于各种不同的flow, 页面id都可以叫做view, 通过_pageId=view来访问。
  Apache软件基金会旗下有一个beehive项目, http://beehive.apache.org/docs/1.0m1/pageflow/pageflow_overview.html, 其中也定义了所谓pageflow的概念, 这是始创于BEA的一项技术. 但是与Witrix Page Flow不同的是, Beehive Page Flow的核心概念仍然是从struts引申而出的action的概念,所谓的flow是action的连接,而不是通过资源id之间的连接。虽然beeive宣称支持各种对象injection, 并且管理了flow对象的生命周期,但是它并没有规范出this指针这一面向对象最重要的概念之一。Witrix Page Flow关注的重点是已存在的页面之间的有效组织, 它所描述的是某种具有静态资源语义的页面模板之间的关联, 这种关联是较松散的,而不是通过action强关联的. 实际上基于Ajax技术和jsplet框架的消息路由机制, 在每一个页面上都可以进行多种业务操作,甚至更换页面,而不发生pageId的变动, 并不是所有的操作过程都需要在page flow描述中对外暴露。另外一个比较细节化的不同之处是Beehive使用Java Annotation, 而Witrix PageFlow使用xml描述文件, 并实现了pageflow的继承和部分覆盖等高级构造方法. 使用xml描述文件的必要性在于需要复用WebAction, 支持复杂的变换操作, 并集成tpl模板引擎等. Annotation的方式看似简单,但这种简单性同时将系统中的所有组分绑定到了一起, 它也不允许复杂的变换操作的存在. 实际上Beehive的目标并不是真正支持页面编制(包括页面上的页面操作)和页面组织的分离.

Feedback

# re: PageFlow: Managed Navigation  回复  更多评论   

2006-11-06 08:53 by pear
不好意思,问个问题,我对PageFlow不是很理解,是不是有了PageFlow,那么页面部分用部分刷新后可以导航回原来的状态呢?
刚开始我还以为PageFlow是一个大于request,小于session的用来保存东西的东东。

# re: PageFlow: Managed Navigation  回复  更多评论   

2006-11-06 22:40 by canonical
一种flow关注的重点当然是协调某种类型实体之间的动态关系,这其中必然需要一种机制来保持状态信息。PageFlow肯定需要一种大于request而小于session的状态保持机制. Jsplet框架就提供了这种机制,而PageFlow是运行在其上的一个引擎。

# re: PageFlow: Managed Navigation  回复  更多评论   

2006-11-07 13:28 by pear
@canonical
这么说,我们可以用Jsplet来保存数据库查出来的东西了,请问这样做有问题吗?如果不想把数据库查出来的数据放到session里面,想问问是不是大家都只是把信息(除了用户信息)放到request里面?或者我们最好把查出来的数据放到哪里比较好?

# re: PageFlow: Managed Navigation  回复  更多评论   

2006-11-07 23:27 by canonical
数据到底是保存在session中还是request中,对于这个问题,基本上它的答案就是应该保存在哪里就保存到哪里。 对于一般简单的网页,应该少在session中存放变量,而对于复杂的企业应用,在session中保持状态是必要的,不过查出的数据一般放在request中就可以了。

# re: PageFlow: Managed Navigation  回复  更多评论   

2007-01-03 00:10 by 江上一叶舟
前一段时间做一个工作流,用的是Websphere Process Server,由于中国式的工作流与国外的大不相同,诸如领导审批类的人工审批节点占据了大多数于是我们的团队遇到了困难,即一个人审批过后接下去可能要接着审批,也可能就交给下一个人来审批,可能此人审批完毕后要将控制权交还给流程引擎,而流程引擎却无法让我们的页面自动跳转,为此我们咨询了IBM美国实验室的WPS高级架构师,他说IBM将在2006年底推出WPS的最新版本,其中引入了PageFlow的概念,由页面来驱动流程的进行,一番讨论后对PageFlow有了一些了解,今见此文,更有了一些自己的见解,十分感谢作者。

# re: PageFlow: Managed Navigation  回复  更多评论   

2007-01-03 16:15 by canonical
Workflow中需要页面和流程配合的部分在Witrix中主要通过前台js选择实现,流程引擎实现的是事件响应而不是驱动界面。 这里倒不太用得上我所谓的PageFlow。 实际上我是反对基于action的flow设计的。

# re: PageFlow: Managed Navigation  回复  更多评论   

2007-05-29 00:20 by ww
very good@pear

只有注册用户登录后才能发表评论。


网站导航:
博客园   IT新闻   Chat2DB   C++博客   博问