首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

用 continuation 开发复杂的 Web 应用程序(4)示例应用程序

用 continuation 开发复杂的 Web 应用程序(4)示例应用程序

示例应用程序我要用一个简单的应用程序,以便您能够很容易使用 continuation 进行 Web 应用程序开发。从导航的角度来看,这个购物应用程序的界面相当简单。在访问应用程序的第一个页面时,要求用户输入想要购买的产品的价格和数量。在输入这些信息,并选择 Next 之后,用户被带到下一屏幕,要求输入用户的分类代码,通过分类代码可以决定用户在该用户的采购金额上能否得到折扣。(请注意,在这个过于简化的示例中,我们假设用户提供的都是真实信息。)在这页上,要求用户选择送货方式是送货上门还是自取。如果选择了送货上门,那么界面返回第三个屏幕,这个屏幕中的用户必须选择送货的类型:标准送货或快运,各自的成本不同。如果用户选择自取,或者完成了送货选择,这里显示最后一个屏幕。这个屏幕中有许多信息,其中有本次购买的总额,这个总额等于购买总额减去分类折扣和运费。
这是一个简单的应用程序,但是对于学习 continuation 的内容,它是一个很好的基础。在我开始编码之前,我要花一分钟针对那些不了解、不喜欢 Apache Cocoon 框架的人对这个框架进行介绍。
关于开发环境示例应用程序的开发环境是在 Windows XP 工作站上的 Apache Tomcat Server(V5.0.18)上运行的 Cocoon  V2.1.5.1。我假设您已经下载了 Cocoon 源代码,构建它,并把生成的 Cocoon Web 应用程序部署到 Tomcat。这样,本文中的源代码就仅仅针对示例应用程序了。如果您需要 Apache Cocoon 的更多下载和设置信息,请参阅 。      

Apache Cocoon 中的 Web continuationApache Cocoon 是一个 Web 开发框架,它允许您用 XSL 转换动态地发布 XML 内容。Cocoon 对不同转换的支持意味着您可以很容易地用多种格式表示内容。Cocoon 用处理管道描述处理请求以及生成对应的响应的时候执行的步骤顺序。每个管道均描述了一种获取输入的方式,接着一系列在数据上执行的处理步骤,以及最后生成输出的机制。
为了形成管道而加入的每个组件都在叫做        站点地图的结构中定义和组织。您可以为一个 Web 应用程序定义多个管道,并指定根据请求 / 环境参数,调用不同的管道处理不同的请求。     
Cocoon 提供的组件可以分成许多类型:
  • 生成器和读取器是管道的输入组件。
  • 转换器和动作是处理组件。
  • 序列化器是输出组件。
  • 匹配器和选择器负责处理条件处理(conditional processing)。
管道要有用处,必须清楚地包含至少一个生成器或读取器,以及一个序列化器。处理步骤的数量取决于应用程序的业务逻辑。
Cocoon 和 MVC上面描述的 Cocoon 架构对应着 MVC 的模型 1 架构,在这个架构中缺少一个负责分派客户层请求并选择视图的中央控制器。但是,Cocoon 也有一个分支是用于模型 2 架构的。在这个例子里,除了正常的管道入口之外,站点地图还必须包含一个入口来指定控制器。像在其他模型 2 架构中一样,控制器负责导引与应用程序模型交互的业务逻辑的方向。在这个例子中,仍然用管道的概念来处理视图,但是管道由控制器驱动。
Cocoon 支持的第一个控制器引擎基于 Mozilla 的 Rhino JavaScript 版本,因为这个版本以第一级对象的形式提供了对 continuation 的支持。正如您将在以下示例中看到的,在控制器中使用 Cocoon 意味着您必须把整个应用程序编写成一个 JavaScript 程序,并把它注册成 Cocoon 应用程序指定的站点地图的流控制器(flow controller)。
要理解这些内容,读代码要比讲概念容易得多。我要做的第一件事是设置购物应用程序的站点地图。然后我们进一步查看用 JavaScript 如何实现应用程序逻辑。最后,我会查看应用程序的某些页面底层的 XML 文件,演示一些重要的概念。
应用程序站点地图示例购物应用程序的站点地图如清单 3 所示:
清单 3. 示例应用程序的 Cocoon 站点地图
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
<?xml version="1.0"?>
<map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">
<map:flow language="javascript">
   <map:script src="pos.js"/>
</map:flow>
<map:pipelines>
   <map:pipeline>
     <map:match pattern="page/*">
       <map:generate type="jx" src="screens/{1}.xml"/>
       <map:transform src="context://samples/common/style/xsl/html/simple-page2html.xsl">
         <map:parameter name="servletPath" value="{request:servletPath}"/>
         <map:parameter name="sitemapURI" value="{request:sitemapURI}"/>
         <map:parameter name="contextPath" value="{request:contextPath}"/>
         <map:parameter name="file" value="/samples/flow/jxrate/screens/{1}.xml"/>
       </map:transform>
       <map:serialize/>
     </map:match>
   </map:pipeline>
   <map:pipeline>
     <map:match pattern="continue.*">
       <map:call continuation="{1}"/>
     </map:match>
     <map:match pattern="">
       <map:call function="sellItem"/>
     </map:match>
   </map:pipeline>
</map:pipelines>
</map:sitemap>




XML 文件中的第一个块(        flow)向 Cocoon 声明:Flowscript 解释器必须用 JavaScript 作为目标语言,实现应用程序的流逻辑(flow logic)的源代码在文件 pos.js 中。     
下一个代码块则实际声明了应用程序要使用的管道。它定义了以下三个管道:
  • 任何对资源的请求,如果资源的 URI 与正则表达式           page/*匹配,就会激活站点地图中声明的第一个管道。要在这个管道中使用的生成器叫做           jx,它基本上是一个标准的生成器组件,由叫做           XTemplateGenerator的 Cocoon 组件提供。          JXTemplateGenerator是一个页面模板处理器,它允许您把 Cocoon Flowscript(在示例应用程序中是 pos.js 文件)传递过来的来自 JavaScript 中的数据插入管道。正则表达式中的           *部分根据输入的请求提取特定的值,然后生成器可以通过           {1}使用这个值。这样,对 URI           page/A的请求会使           JXTemplateGenerator把 screens/A.xml 作为源代码。
  • 任何对资源的请求,如果资源的 URI 与正则表达式           continue.*匹配,就会激活第二个管道。您可以看到,示例应用程序把 continuation           id作为表单要提交的 URL 的一部分,从而把 continuation           id传递给浏览器。像以前一样,实际的 continuation           id作为           {1}使用。          call元素实际上要求继续执行由           {1}当前持有的值标识的 continuation。          call元素还有第二个变体,您接下来会看到。
  • 与在站点地图中声明的最后一个管道匹配的请求,实际上是与前两个正则表达式不匹配的任何请求(例如,对应用程序发出的第一个请求发向 URI“          /”,然后激活这个管道)。在这里,          call元素要求站点地图调用 Flowscript(pos.js)中定义的顶级函数           sellItem。实际的效果是:对应用程序(URI "          /")的第一个请求会开始 pos.js 的执行。
请注意,所有组件一般都要在站点地图中声明。我不需要声明清单 3 中的应用程序组件,因为我把示例应用程序作为 Cocoon 示例的一部分运行,其中有一个顶级站点地图,已经替我声明了这些组件(例如         jx)。     
应用程序逻辑
返回列表