Struts是源代码开放的企业级Web应用开发框架,它的设计目的是从整体上减轻构造企业Web应用的负担。本文通过一个Struts应用的实例,帮助你迅速掌握Struts。
Struts是在Jakarta项目下开发的源代码开放软件,由一系列的框架类、辅助类和定制的JSP标记库构成,定位在基于Model
2设计模式的J2EE应用开发。Model 2体系是MVC(Model-View-Controller)体系的一种应用。在MVC体系中,数据模型(Model)、表现逻辑(View)和控制逻辑(Controller)是分离的组件,但它们可以互相通信。Struts力图从整体上减轻构造企业级Web应用的负担,并提供国际化和数据库连接池支持。
Struts体系可以看成两个相对独立的部分:第一个部分是Struts
API,用于编写支持Struts的应用组件;第二部分是Struts的JSP标记库,由html、bean、logic和template四个标记组成。Struts的两个部分有着各自不同的用户。对于规模较小的项目,同一个用户可能同时使用这两个部分;但对于规模较大的项目,通常开发者使用API组件,而负责HTML页面布局的人使用标记库。
Struts的设计目标是为Model 2 Web应用开发提供一个强大的框架。同时,Struts还包含了一些实用组件,例如Digest,但这些组件并不从属于上面提到的两个部分。
Struts应用的体系结构
对于从传统编程环境转入Web开发的人来说,Web编程中令人很不习惯的一个特点是缺乏“程序”。传统的应用总是有主入口点、流程控制和出口点。但在Web网站上,用户可能从任何地方进入,按照一种完全随机的次序访问各个页面,甚至可能跳过多个页面,也可能在一、两个小时内毫无动静。这是HTTP访问的基本特征,无论是Struts还是其他Web编程框架,都无法改变这一点。然而,Struts能够隐藏Web访问固有的“混乱”,帮助开发者建立起清晰和明确的秩序和规则。
在Struts应用中,有一个称为ActionServlet的主调度程序(或称为分配器),如图1所示。不过,并非所有的请求都必须通过ActionServlet。用户的请求目标可以是非Struts的页面,也可以是那些使用了Struts标记库但不使用Struts请求分配服务的页面。这正是Struts体系的优点之一:按需使用。许多编程框架要求你要么不用,要么全部使用,而且一旦你决定使用,以后要悔改从前的错误就会付出高昂的代价。Struts按需使用的优点与这类系统形成了强烈对比。
图1 Struts框架中的请求处理
Struts应用由下面这些基本模块构成:
1.配置信息;
2.Servlet,主要是Struts的ActionServlet;
3.动作类(Action),执行逻辑和控制(请求分配)功能,它们由ActionServlet调用;
4.JSP页面(属于View),常常通过动作类分派;
5.JSP标记库,根据需要使用;
6.各种形式的JavaBean,包括用户定义的JavaBean。
典型的Struts应用要用到三种配置文件:web.xml、struts-config.xml和可选的应用资源文件。
web.xml是Web应用的标准配置文件,是所有J2EE Web应用必需的组成部分。应用服务器通过该配置文件把URL映射到Servlet和JSP,通过该配置文件为Servlet和JSP指定启动参数。为Struts应用提供的基本web.xml文件很简单,真正必需的只有一个主ActionServlet定义,以及一个确保Struts请求传递到ActionServlet的映射。按照惯例,以“.do”结尾的URL都是Struts请求,例如/login.do。应用服务器利用web.xml文件中的映射,把该请求传递给ActionServlet。接着,ActionServlet决定如何分配该请求。ActionServlet的决定依据是struts-config.xml中定义的规则,和/或是通过ActionServlet派生类额外定义的分配逻辑。
struts-config.xml称为Struts配置文件。Struts应用是一个依靠struts-config.xml文件把组件连接起来的网络。struts-config.xml文件为Web应用的组件定义了逻辑名称,也定义了它们在Struts框架下的属性和关系,就像web.xml文件在Web应用框架之内定义组件一样。struts-config.xml文件包含了与Struts框架有关的应用信息,这些信息分四个类:
1.数据源信息,它是可选的。在这里可以指定一个或者多个JDBC数据源,使得数据库定义信息集中化。对于数据库访问,Struts还有一个额外的优点,即支持基本的数据库连接池功能。
2. Form Bean是JavaBean的一种特殊类型,它简化了Web表单的处理。
3. Global Forwards是全局性的转发定义信息。Struts动作按照一种“请求—转发”机制运行。为了最大限度地分 离动作模块与转发目标,这里使用了一种映射机制,允许通过同义词引用转发目标。一些目标页面可能被多个动作类引用,例如登录页面,因此可以在全局转发定义部分把逻辑目标页面映射到物理目标页面,避免把这部分信息加入到动作定义部分。
4. Actions定义了Struts应用体系的请求分配信息,它们是核心分配器的补充定义,负责处理各种具体的请求类型。
一个简单的应用
基于Struts的Web应用和普通Web应用有着许多同样的要求,但Struts应用也有自己特殊的需求。一个可部署的Web应用应该可组织和构成一个WAR文件。WAR文件是带有图2所示目录结构的JAR包。对于Struts
Web应用来说,Web-INF目录下还要加上一些额外的文件,例如struts-confg.xml文件和标记库描述器(TLD)文件。注意:应用的资源应该放入应用的类路径下,也就是Web-INF/lib目录或Web-INF/class目录下的JAR包内。对于大多数简单的Struts页面,我们只用到Struts标记库,而按照MVC的术语就不需要涉及Model和Controller部分,只涉及View。请看图3所示的主页例子。虽然这个页面没有表单,但Struts仍能够在设计这类页面时提供帮助。
图2 Struts应用的目录结构
图3 一个简单的View
要管理会话,最简单的途径是使用Cookie。会话标识符被传递到客户端之后,客户端把它保存到Cookie,以后的每次请求就把Cookie发送到服务器。然而,和其他的许多Web解决方案一样,Cookie方案也不是万能的,因为一些用户可能不信任Cookie,关闭浏览器的Cookie支持。由于这种情况,URL改写技术就出现了。使用URL改写技术时,整个网站的所有URL后面都将加上会话标识符。虽然这个方案不像采用Cookie方案那样简单、稳固,但它确实行得通。URL改写技术的不稳固是有两方面的原因。首先,和Cookie不同,URL没有过期时间,如果一个带有会话标识的URL被截取后又重新在以后的访问中使用,那么这种URL不会很有用,因为会话一般在一定的时间后会被作废。其次,如果有一个URL链接的后面没有带上会话标识符,整个链都会中断,客户程序无法再次获取会话标识符,除非它备份了带有会话标识符的URL访问历史。
Servlet能够只通过一次方法调用完成URL改写。从技术上讲,JSP也一样能够办到这一点,但一个好的JSP页面应该不包含Java代码,或包含尽量少的Java代码。为此,Struts提供了一个链接标记。本例使用了该标记来维持客户端和服务器之间的会话状态信息。
绑定View、Model和Controller
前面的简单页面不需要Struts分配器,因为它只有简单的链接。图4显示了一个比较复杂的“类别”页面。它列举出了数据库中的类别条目,并将这些条目分别链接到对应的编辑页面。为显示这个页面,我们就要用到Struts的ActionServlet分配机制。
图4 类别页面
在web.xml文件中,放入一项表示所有以“.do”结尾的URL请求必须发送给Struts分配器的声明。这里的分配器可以是org.apache.struts.action.ActionServlet或其扩展类。Struts分配器在启动时读取struts-config.xml文件,并构造出一个动作映射图。本例指定了一个名为ShowCategories的动作类,来处理“ShowCategories”动作。可以看出,Struts应用的基本工作模式是:主分配器调用一个动作分配器,动作分配器确定或构造出Model部分(一个JavaBean或其它Java对象),并把它提供给View(通常是一个JSP页面)。
本例使用Bean的情况稍微有点复杂,它有多个数据项,因此我们不是使用单个提供数据的Bean,而是要生成一组Bean。遗憾的是,JSP页面以HTML为基础,HTML没有提供循环或其他控制逻辑。不过,Struts的logic:iterate允许对数组进行迭代操作,如下面的代码片断所示:
<table>
<logic:iterate id="category"
type="com.strutsdemo.Category"
name="<%= Constants.CATALOG_CATEGORIES %>"
scope="application">
<tr>
<td>
<html:link page="/editCategory.do"
name="category"
property="mapping">
编辑
</html:link>
<html:link page="/removeCategory.do"
name="category"
property="mapping">
删除
</html:link>
<bean:write name="category"
property="category"/>
</td>
</tr>
</logic:iterate>
</table>
|
上面讨论了Model 2体系的Model和View部分,下面来看看Controller部分。Struts体系有一个主控制器,即ActionServlet。ActionServlet负责选择和调用合适的动作控制器—即org.apache.struts.action.Action的扩展类。动作控制器实现了process()方法。process()方法分析从URL请求传入的每一个参数,执行必要的业务逻辑,并返回一个指定了调用链中下一个链接的动作(通常是View)。在本例中,我们想要从数据库提取数据,创建管理这些数据的JavaBean,把多个JavaBean整理成一个数组,再把数组保存到请求的上下文,从而使得作为View的JSP页面能够方便地进行页面布局。
|