Web 框架设计与实现 ( 一 ):Maverick

在 j2ee 项目工程中合理的使用 web 框架能有效提高工作效率,增强程序的可维护型和可扩展性。目前比较流行的是基于 mvc 模式的 struts 结构,但在开源项目的宝库中,除了 struts 外,还有其他许多独具匠心、性能优异的框架结构,如 Maverick WebWork SpringTapestryTurbine等,存在自有存在的理由和价值,只有了解了其他框架的设计思想和性能特色,才能在项目实践中根据客户需求灵活选择更合适的设计框架,本文主要介绍 maverick 框架的设计与实现。

0 评论:

合易 ([email protected])中和开源工作室

2003 年 9 月 10 日

  • +内容

在 IBM Bluemix 云平台上开发并部署您的下一个应用。

现在就开始免费试用

mvc 模式也许是软件设计中最经典的设计模式了,Smaltalk 类库的模型 视图 控制器三元组结构触动了软件设计的灵感,清晰的层次结构、明确的职责范围、流畅的工作流程使软件设计增添了艺术的美感。Maverick 框架便隐藏着这种美感,(名字中隐含着 mvc 的意思)。Maverick 框架致力于实现 mvc 模式,其 1.0 版本于 2001 年早期发布,两名主要开发者之一的 Jeff Schnitzer 也是开源社区著名测试工具 JuitEE 的创作者,目前的最新版本是 2.2。

快速开始

在深入探索 Maverick 的基本理论和设计思想之前,让我们通过对 friendbook-jsp 实例的配置,快速体验一下 Maverick 的功能和魅力。

1、 下载 Maverick 基本框架和文档。(参考资料有下载地址)Maverick 分为基本框架和扩展框架,基本框架包括在 Maverick-2.2.0.zip 中,扩展框架包括 opt-domity、 opt-betwixt 、opt-fop、 opt-velocity、opt-perl、opt-struts 可根据需要选择下载。

2、 解压缩 Maverick-2.2.0.zip 文件,在 Maverick 的 examples 目录下运行 ant ,在 build 文件夹下生成 friendbook-jsp.war 文件。

3、 假如我们用 Tomcat 4.0 进行调试,拷贝 friendbook-jsp.war 文件到 tomcat-4.0/webapps 目录中,拷贝 Maverick / lib 目录下的 log4j.jar 文件到 tomcat-4.0/lib 下。如果你系统的 jdk 版本低于 1.4 还须拷贝 Maverick/ lib 目录下的 xml-apis.jar 文件到 tomcat-4.0/lib 下。

4、 启动 tomcat 在浏览器中键入:http://localhost:8080/friendbook-jsp, 可以看到如下界面:

Web 框架设计与实现 ( 一 ):Maverick

根据演示流程的运转,打开源代码,参考本文的技术介绍,就可以开始你的 Maverick 探索之旅了。

回页首

功能特征:

Maverick 宣称集成了 Struts、Webword、Cooco 中最好的特性,是一个简洁灵活、彻底实现 mvc 模式的抽象框架,允许你采用不同的模板和转换技术实现表示层逻辑。具体特性如下

5、 简洁实用、易于理解。遵循简洁的设计是最好实现的原则,提供给你最需要的东西。其核心层设计简洁、功能强大、扩展性强。

6、 采用插入式扩展集成的设计思想,核心工作流程简洁明了,能在最短的时间内以最小的学习成本理解框架的精髓。扩展模块范围广、功能强、能灵活运用。

7、 完全独立的表示层设计。根据喜好可选择 JSP(基于 JSTL 标准) Velocity Domify/XSLT 等。

8、 可配置的转换管道。能实现 Javabean 数据到 XML 的透明转换,包括支持 XSLT, DVSL, FOP, Perl. 等的转换。

9、 基于标准 XML 的配置。

10、 同时支持 Struts 类型的独立控制器和 Webwork 类型的 "throwaway" 控制器。

11、 多平台的实现。可扩展到 .NET 和 PHP.

回页首

框架结构和流程分析:

Maverick 框架是标准的 mvc 模型设计,有清晰的层次结构和职责划分,下面是其实现简图:

Web 框架设计与实现 ( 一 ):Maverick

其基本工作流程表述如下:

1、 和 Struts 框架一样,Maverick 使用一个统一的控制器 servlet 作为切入点,由 org.infohazard.Maverick.Dontroller 类实现,定义在 web.xml 文件中,所有的 URL 都映射到 Controller 类上。当一个 HTTP 请求发送到 Controller 类中时 Controller 从 /WEB-INF/Maverickl.xml 中获得配置,生成 org.infohazard.Maverick.flow.Controller 对象的实例,此应用控制器一般继承 ThrowawayBean2 超类。 在此应说明的是 Maverick 不同于 Struts, 其请求控制器通常是 javabean 组件,不区分控制器(Action)和命令(ActionForm)这样做的好处是每个新控制器不必是线程安全的,不必要支持并发调用,但同时也导致控制器实例的增值。

2、 应用控制器的组件属性通过反射从请求参数中进行设置,使用 Apache Commons BeanUtil 包进行填充。

3、 调用应用控制器的 perform() 方法,在执行过程中通过 ControllerContext 对象的 setModle() 方法设置视图所显示的模型对象,并且在调用了业务对象之后返回 Maverick.xml 中定义的视图名称。

4、 由 setModle() 方法所设置的模型对象以关键字"modle"放置在 servlet 的请求属性中。

5、 执行 JSP 或 Valocity 的视图模板。或用模型对象生成 XML, 通过 Maverick.xml 中定义的 xsl 文件把 xml 转化成 XSLT 并返回到客户端。

上述工作流程仅描述了基于 ThrowawayBean2 超类的应用控制器配置,而 Maverick 提供了四种不同应用控制器类型的扩展: ThrowawayBean2、FormBeanUser、ThrowawayFormBeanUser、ControllerWithParams,这使 Maverick 的工作流程可由客户自定义,实现了框架的高度可配置性。

Web.xml 配置文件

配置 Web.xml 是开发 Maverick 的第一步,所有的命令(commons)都以"* .m"的扩展名映射到 Controller servlet 中。

 <web-app> 
  <display-name>Friendbook Web Application</display-name> 
	
  <servlet> 
    <servlet-name>dispatcher</servlet-name> 
    <display-name>Maverick Dispatcher</display-name> 
    <servlet-class>org.infohazard.Maverick.Dispatcher</servlet-class> 
    <load-on-startup>2</load-on-startup> 
  </servlet> 
  <servlet-mapping> 
    <servlet-name>dispatcher</servlet-name> 
    <url-pattern>*.m</url-pattern> 
  </servlet-mapping> 
 </web-app>

从上述可看出 Maverick.xml 文件与 struts 是非常相似的。

Maverick.xml 配置文件

Maverick 的配置文件与 struts 相比是简介易懂的,它没有繁琐的 DTD 困扰你,一切都简洁明了,一目了然。如下所示:( 选自 Maverick 下载包 friendbook-jsp 实例 )

 <?xml version="1.0"?> 
 <!-- 
	 $Id: Maverick.xml,v 1.6 2003/01/12 04:03:22 lhoriman Exp $ 
	 $Source: /cvsroot/mav/Maverick/examples/friendbook-jsp/WEB-INF/Maverick.xml,v $ 
 --> 
 <Maverick version="2.0" default-view-type="document" default-transform-type="document"> 
	 <views> 
		 <view id="loginRequired" path="loginRequired.jsp"> 
			 <transform path="trimOutside.jsp"/> 
		 </view> 
	 </views> 
	 <commands> 
		 <command name="welcome"> 
			 <view path="welcome.jsp"> 
				 <transform path="trimOutside.jsp"/> 
			 </view> 
		 </command> 
		 <command name="loginSubmit"> 
			 <controller class="org.infohazard.friendbook.ctl.LoginSubmit" /> 
			 <view name="success" type="redirect"/> 
			 <view name="error" path="loginFailed.jsp"> 
				 <transform path="trimOutside.jsp"/> 
			 </view> 
		 </command> 
 ...... 
 </commands> 
 </Maverick>

在上述配置文件中可发现有三个基本概念需要理解:command controller view 。

  • command <command> 是 Maverick 框架的基本单元,它定义了一个 Maverick 应用程序在运行时的基本特征,它包含 <controller> <view> 等子元素,其 name 属性定义了一个 command 元素的名字,当来自 HTTP 请求的 URL 与之匹配时,command 被执行:访问 controller 定义的应用控制器,返回 view 定义的视图。

  • Controller 子元素是可选择的,当一个 command 的 controller 子元素未定义时,其请求直接返回 view 定义的视图。 controller <controller> 元素包含在 command 中,它定义了一个执行请求的用户类(即应用控制器),该类一般继承自 ThrowawayBean2 超类,集成了 struts 中 Action 和 ActionForm 的功能,通过 perform() 方法返回 view 定义的视图。Maverick 也支持 struts 类型的单独控制器流程。可通过继承 FormBeanUser 超类灵活配置。

  • view <view> 元素定义了表示层的视图模型,在 Maverick.xml 文件中它一般定义在两个位置,1、作为 Maverick 的子元素,它定义了一个全局变量式的全局视图,如

     <views> 
    		 <view id="loginRequired" path="loginRequired.jsp"> 
    			 <transform path="trimOutside.jsp"/> 
    		 </view> 
    	 </views>

    视图 loginRequired 可被其他定义在 command 中的 view 元素访问。其 id 属性是必须指定的。它可与其他 view 元素的 name 和 ref 属性相关联。

    2、作为 command 的子元素。它定义了一个与 command 相联系的局部视图,可通过 ref 属性与全局视图的 id 属性相关联,访问全局视图。如

     <command name="editSubmit"> 
    			 <controller class="org.infohazard.friendbook.ctl.EditSubmit"/> 
    			
    			 <view ref="loginRequired"/> 
    			 <view name="success" type="redirect" path="friends.m"/> 
    		 </command>

    command 中的 <view> 有一可选元素 <transform>, 它用" wrapped"关键子与包含它的视图集成在一起。如 trimOutside.jsp 中的 <c:out value="${wrapped}" escapeXml="false"/> 在运行过程中"wrapped"被包含它的 welcome.jsp 替换。使 welcome.jsp 和 trimOutside.jsp 集成在一起。

回页首

应用控制器的配置

如前所述 ,Maverick 框架具有高度可配置性,可以实现用户自定义流程管理,其提供的主要超类有四种: ThrowawayBean2:ThrowawayBean2 继承了 Controller 接口,是标准的 javabean 组件,它采用 controller-as-modle 模式,把组件属性和控制逻辑集成在一起,充当了 struts 中 Action 和 FormAction 两个角色,如下例所示:

 public class LoginSubmit extends ThrowawayBean2 
 { 
	 public static final String DEFAULT_DEST = "friends.m"; 
	 protected String name; 
	 public String getName() 				 { return this.name; } 
	 public void setName(String value) 	 { this.name = value; } 
	 protected String password; 
	 public String getPassword() 				 { return this.password; } 
	 public void setPassword(String value) 	 { this.password = value; } 
	 protected String dest; 
	 public String getDest() 				 { return this.dest; } 
	 public void setDest(String value) 	 { this.dest = value; } 
	
	 protected String perform() throws Exception 
	 { 
		 if (!this.login(form.getName(), form.getPassword(), ctx)) 
		 { 
			 return ERROR; 
		 } 
		 else 	
		 { 
				 if (this.dest == null || this.dest.trim().length() == 0) 
				 this.getCtx().setModel(DEFAULT_DEST); 
			 else 
				 this.getCtx().setModel(this.dest); 
			
			 return SUCCESS; 
		 } 
	 } 
 }

LoginSubmit 类用 get() 和 set() 方法定义了三个受保护的属性:name 、password、 dest,重写了继承自 Throwawaybean2 的 perform() 方法,调用 ControllerContext 类的 setModel() 方法建立视图模型,并返回视图名称。LoginSubmit 类集成了组件属性和控制逻辑,并以关键词"modle"放置在 servlet 的请求属性中。在表示层的 JSP 文件中以 modle.xxx 的表达式暴露其属性值。如

 <td> 
	 <input value="<c:out value="${model.name}"/>" name="Password" > 
 </td> 
 <td class="Text"> 
	 <c:out value="${model.password}"/> 
 </td>

FormBeanUser:FormBeanUser 类继承 ControllerSingleton 接口,是单独的控制器类,它引用定义在外部的 FormBeanl 类,而不是把组件属性定义在自身,它必须是线性安全的。如果你想把模型(modle)保存在 session 中或不喜欢 Throwawarybean2 的零乱结构,可采用此控制器流程,它和 Struts 结构的 Actions 非常相似。上例的 LoginSubmit 类可改写如下:

 public class LoginSubmit2 extends FormBeanUser 
 { 
	
	 public static final String DEFAULT_DEST = "friends.m"; 
	
	 protected Object makeFormBean(ControllerContext cctx) 
	 { 
		 return new Form(); 
	 } 
	 protected String perform(Object formBean, ControllerContext ctx) throws Exception 
	 { 
		 Form form = (Form)formBean; 
		
		 if (!this.login(form.getName(), form.getPassword(), ctx)) 
		 { 
			 return ERROR; 
		 } 
		 else 	 // they are now logged in... 
		 { 
			 // Target of redirect 
			 if (form.getDest() == null || form.getDest().trim().length() == 0) 
				 ctx.setModel(DEFAULT_DEST); 
			 else 
				 ctx.setModel(form.getDest()); 
			
			 return SUCCESS; 
		 } 
	 } 
 }

其引用的 Form 类定义如下:

     public class Form 
     { 
         protected String name; 
         public String getName()                  { return this.name; } 
         public void setName(String value)      { this.name = value; } 
        
         protected String password; 
         public String getPassword()                  { return this.password; }
         public void setPassword(String value)      { this.password = value; } 
        
         protected String dest; 
         public String getDest()                  { return this.dest; } 
         public void setDest(String value)      { this.dest = value; }
     }

在 JSP 文件中可如下调用:

<input value="<c:out value="${model.form.name}"/>" name="Password" > 
ThrowawayFormBeanUser: 此类是 ThrowawayBean2 和 FormBeanUser 类的混血儿,
    它即遵循 ThrowawayBean2 的流程又准许调用外部的 FormBean 类。ControllerWithParams:带有参数访问的控制类。如:
<controller class="Login"> 
<param name="secure" value="true"> 
</controller>

通过这四种控制器类型的扩展,Maverick 框架提供了灵活的流程控制,最常用的是扩展 ThrowawayBean2 类的控制流程,但熟悉 Struts 框架的读者可能对实现 FormBeanUser 的扩展更亲切一些。Maverick 下载包中包含了 friendbook-jsp 和 friendbook-jsp-fbu 两个实例分别实现了扩展 ThrowawayBean2 和 FormBeanUser 的流程控制,读者可根据源码细心体会。

回页首

视图表示

与 Struts 绑定与 jsp 视图不同,Maverick 支持多视图表示,避免了控制层与表示层的紧耦合,使表示层的职责更加清晰明确。Maverick 支持 JSP Velocity XSLT 等视图模板。

JSP:

JSP 是使用最广的视图模板,它具有强大的表示和控制功能,在 Modle1 的设计框架中承担了关键角色。但在 Maverick 框架中它被限制在视图表示的职责范围内。Maverick 支持 JSP 的标准标签库 JSTL,不提供自身的特殊标签库,降低了学习难度,避免了框架对专有知识的依赖。

在 Maverick 中实现 JSP 是非常简单的,在 Maverick.xml 配置文件中如下设置:

    <Maverick version="2.0" default-view-type="document" 
	default-transform-type="document"> 
    <views> 
         <view id="loginRequired" path="loginRequired.jsp">
             <transform path="trimOutside.jsp"/> 
         </view> 
     </views>

Maverick 元素的 default-view-type 属性设置为"document",以便访问 JSP 文档,JSP 通过放置在 servlet 请求属性中的 modle 关键字引用控制器类的属性和方法。

Velocity:

Velocity 是 jakarta apach 的开源项目,它是一个纯粹的模板引擎,不依赖于 servlet API, 可用于除 web 程序之外的其他应用,并可在 servlet 容器外部测试。Velocity 的核心是 Velocity Template Language(VTL), 该模板语言的属性导航语法与 JSP 的 JSTL 差不多,易于学习和理解。

Velocity 是一种简单而高性能的模板语言,能有效暴露控制器类的属性和方法,实现控制器逻辑和视图模板的彻底分离。在 Maverick 中实现 Velocity 也很简单,首先在 web.xml 配置文件中注册 VelocityViewServlet,如:

     <servlet> 
         <servlet-name>velocity</servlet-name> 
         <servlet-class>
         org.apache.velocity.tools.view.servlet.VelocityViewServlet
         </servlet-class> 
         <load-on-startup>10</load-on-startup> 
     </servlet> 
     <servlet-mapping> 
         <servlet-name>velocity</servlet-name> 
         <url-pattern>*.vm</url-pattern> 
     </servlet-mapping>

其次,在 Maverick.xml 配置文件中,设置 Maverick 元素的 default-view-type 属性设置为"document", 如 JSP 一样通过放置在 servlet 请求属性中的 modle 关键字暴露控制器类的属性和方法。(Maverick 下载包中不包括 velocity, 可另下载 opt-velocity 扩展包)。

XSLT

XSLT 是 XML 转换语言,纯粹是为转换数据而设计的,在 web 应用中常用于 XML 数据的转换,但不能用来处理用户请求。Maverick 对 XSLT 的支持是通过 opt-domify 扩展包实现的,Domify 利用 java 反射实现 model 模型到 DOM 的适配。 实现 JavaBean 数据到 XML 的透明转换,是 Maverick 的特点之一,现在 Maverick 的数据转换库是一个独立的开源项目。另外,Maverick 还提供一个可配置的转换管道,可配合 XSLT 一起使用。(opt-domify 扩展包有一 friendbook 实例,读者可深入研究)。

回页首

可扩展的功能模块:

强大的扩展功能是 Maverick 吸引人的特性之一,可插入式的扩展模块,是实现此功能的关键。与 eclipse 的 plug-in 相似,Maverick 核心层提供了可配置的模块接口机制,可选的扩展模块能根据客户需求提供灵活的解决方案。在 Maverick 下载页中提供的可扩展模块主要包括:

opt-domify:Domify 原是 Maverick 框架的一部分,提供 JavaBean 组件到 W3C DOM 表示层的适配,避免了生成 XML 文本的中间环节。现在 Domify 已从 Maverick 中独立出来,成为另一开源项目。如果用 Domify 和 XSLT 作为视图表示层,可选择 opt-odomify 扩展包。

Opt-betwixt:Betwixt 能从 JavaBean 组件中生成一系列 SAX 事件,可代替 Domify 成为 XSLT 表示层的另一选择。

Opt-fop: 提供 Apache FOP 服务,Apache FOP 能把 XSL-FO(XSL 格式化对象)转化成多种表现格式,如 PDF 和 Postscript . 用 opt-fop 扩展包你能用 XSLT 把模型转化为 XSL-FO,然后再转化为 PDF 或其他格式表现出来。

Opt-Velocity: 支持 Velocity 视图模板的功能包,Velocity 的使用如上文所述。

Opt-perl: 提供了一个通过 Perl 运行的 Maverick 转化类型。

Opt-Struts: 提供一系列把 Struts 应用程序转化到 Maverick 框架的工具。

回页首

总结:

与 Struts 相比,Maverick 提供了一个更加灵活的轻量型 web 框架,它的简洁易用和强大的扩展功能吸引了大批使用者。框架的选择和使用是项目开发的重要部分,要根据客户的需求和项目整体功能的要求选择合适的框架,要记住最实用的才是最好的。


你可能感兴趣的:(Web 框架设计与实现 ( 一 ):Maverick)