运用Jakarta Struts的七大实战心法

 
【提问】运用 Jakarta Struts 的七大实战心法

原文 http://www.onjava.com/pub/a/onjava/2002/10/30/jakarta.html?page=1)
( 作者 Chuck Cavaness, 编译 邱文宇 )

编者按:当作者 Chuck Cavaness (著有《 Programming Jakarta Struts 》一书)所在的网络公司决定采用 Struts 框架之后, Chuck 曾经花费了好几个月来研究如何用它来构建公司的应用系统。本文叙述的正是作者在运用 Struts 过程中来之不易的若干经验和心得。如果你是个负责通过 jsp 和 servlet 开发 Web 应用的 Java 程序员,并且也正在考虑采用基于 Struts 的构建方法的话,那么你会在这里发现很多颇有见地同时也很有价值的信息。

1. 只在必要的时候才考虑扩展 Struts 框架

一个好的 framework 有很多优点,首先,它必须能够满足用户的可预见的需求。为此 Struts 为 Web 应用提供了一个通用的架构,这样开发人员可以把精力集中在如何解决实际业务问题上。其次,一个好的 framework 还必须能够在适当的地方提供扩展接口,以便应用程序能扩展该框架来更好的适应使用者的实际需要。

如果 Struts framework 在任何场合,任何项目中都能很好的满足需求,那真是太棒了。但是实际上,没有一个框架声称能做到这一点。一定会有一些特定的应用需求是框架的开发者们无法预见到的。因此,最好的办法就是提供足够的扩展接口,使得开发工程师能够调整 struts 来更好的符合他们的特殊要求。

在 Struts framework 中有很多地方可供扩展和定制。几乎所有的配置类都能被替换为某个用户定制的版本,这只要简单的修改一下 Struts 的配置文件就可以做到。

其他组件如 ActionServlet 和 RequestProcessor 也能用自定义的版本代替 . 甚至连 Struts 1.1 里才有的新特性也是按照扩展的原则来设计的。例如,在异常处理机制中就允许用户定制异常处理的句柄,以便更好的对应用系统发生的错误做出响应。

作为框架的这种可调整特性在它更适合你的应用的同时也在很大的程度上影响了项目开发的效果。首先,由于您的应用是基于一个现有的成熟的、稳定的 framework 如 Struts ,测试过程中发现的错误数量将会大大减少,同时也能缩短开发时间和减少资源的投入。因为你不再需要投入开发力量用于编写基础框架的代码了。

然而 , 实现更多的功能是要花费更大的代价的。我们必须小心避免不必要的滥用扩展性能, Struts 是由核心包加上很多工具包构成的,它们已经提供了很多已经实现的功能。因此不要盲目的扩展 Struts 框架,要先确定能不能采用其他方法使用现有的功能来实现。 在决定编写扩展代码前务必要确认 Struts 的确没有实现你要的功能。否则重复的功能会导致混乱将来还得花费额外的精力清除它。

2. 使用异常处理声明

要定义应用程序的逻辑流程,成熟的经验是推荐在代码之外,用配置的方法来实现,而不是写死在程序代码中的。在 J2EE 中,这样的例子比比皆是。从实现 EJB 的安全性和事务性行为到描述 JMS 消息和目的地之间的关系,很多运行时的处理流程都是可以在程序之外定义的。

Struts 创建者从一开始就采用这种方法,通过配置 Struts 的配置文件来定制应用系统运行时的各个方面。这一点在版本 1.1 的新特性上得到延续,包括新的异常处理功能。在 Struts framework 以前的版本中,开发人员不得不自己处理 Struts 应用中发生的错误情况。在最新的版本中,情况大大的改观了, Struts Framework 提供了内置的一个称为 ExceptionHandler 的类,用于系统缺省处理 action 类运行中产生的错误。这也是在上一个技巧中我们提到的 framework 许多可扩展接口之一。

Struts 缺省的 ExceptionHandler 类会生成一个 ActionError 对象并保存在适当的范围( scope )对象中。这样就允许 JSP 页面使用错误类来提醒用户出现什么问题。如果你认为这不能满足你的需求,那么可以很方便的实现你自己的 ExcepionHandler 类。

具体定制异常处理的方法和机制

要定制自己的异常处理机制,第一步是继承 org.apache.struts.action.ExceptionHandler 类。这个类有 2 个方法可以覆盖,一个是 excute() 另外一个是 storeException(). 在多数情况下,只需要覆盖其中的 excute() 方法。下面是 ExceptionHandler 类的 excute() 方法声明:

正如你看到的,该方法有好几个参数,其中包括原始的异常。方法返回一个 ActionForward 对象,用于异常处理结束后将 controller 类带到请求必须转发的地方去。

当然您可以实现任何处理,但一般而言,我们必须检查抛出的异常 , 并针对该类型的异常进行特定的处理。缺省的,系统的异常处理功能是创建一个出错信息,同时把请求转发到配置文件中指定的地方去。定制异常处理的一个常见的例子是处理嵌套异常。假设该异常包含有嵌套异常,这些嵌套异常又包含了其他异常,因此我们必须覆盖原来的 execute() 方法,对每个异常编写出错信息。

一旦你创建了自己的 ExceptionHandler 类,就应该在 Struts 配置文件中的部分声明这个类,以便让 Struts 知道改用你自定义的异常处理取代缺省的异常处理 .

可以配置你自己的 ExceptionHandler 类是用于 Action Mapping 特定的部分还是所有的 Action 对象。如果是用于 Action Mapping 特定的部分就在 <action> 元素中配置。如果想让这个类可用于所有的 Action 对象 , 可以在 <global- sections> 元素中指定。例如,假设我们创建了异常处理类 CustomizedExceptionHandler 用于所有的 Action 类 , <global-exceptions> 元素定义如下所示:

在 <exception /> 元素中可以对很多属性进行设置。在本文中,最重要的属性莫过于 handler 属性 , handler 属性的值就是自定义的继承了 ExceptionHandler 类的子类的全名。假如该属性没有定义, Struts 会采用自己的缺省值。当然,其他的属性也很重要,但如果想覆盖缺省的异常处理的话, handler 无疑是最重要的属性。

最后必须指出的一点是,你可以有不同的异常处理类来处理不同的异常。在上面的例子中, CustomizedExceptionHandler 用来处理任何 java.lang.Exception 的子类 . 其实,你也可以定义多个异常处理类,每一个专门处理不同的异常树。下面的 XML 片断解释了如何配置以实现这一点。

在这里,一旦有异常抛出, struts framework 将试图在配置文件中找到 ExceptionHandler ,如果没有找到,那么 struts 将沿着该异常的父类链一层层往上找直到发现匹配的为止。因此,我们可以定义一个层次型的异常处理关系结构,在配置文件中已经体现了这一点。

3. 使用应用模块( Application Modules )

Struts 1.1 的一个新特性是应用模块的概念。应用模块允许将单个 Struts 应用划分成几个模块,每个模块有自己的 Struts 配置文件, JSP 页面, Action 等等。这个新特性是为了解决大中型的开发队伍抱怨最多的一个问题,即为了更好的支持并行开发允许多个配置文件而不是单个配置文件。

注:在早期的 beta 版本中,该特性被称为子应用( sub-applications ),最近的改名目的是为了更多地反映它们在逻辑上的分工。

显然,当很多开发人员一起参加一个项目时,单个的 Struts 配置文件很容易引起资源冲突。应用模块允许 Struts 按照功能要求进行划分,许多情况已经证明这样更贴近实际。例如,假设我们要开发一个典型的商店应用程序。可以将组成部分划分成模块比如 catalog (商品目录) , customer (顾客) , customer service (顾客服务) , order (订单)等。每个模块可以分布到不同的目录下,这样各部分的资源很容易定位,有助于开发和部署。图 1 显示了该应用的目录结构。

图 1. 一个典型的商店应用程序的目录结构
按此在新窗口浏览图片

注:如果你无需将项目划分成多个模块, Struts 框架支持一个缺省的应用模块。这就使得应用程序也可以在 1.0 版本下创建,具有可移植性,因为应用程序会自动作为缺省的应用模块。

为了使用多应用模块功能,必须执行以下几个准备步骤:

• 为每个应用模块创建独立的 Struts 配置文件。

• 配置 Web 部署描述符 Web.xml 文件。

• 使用 org.apache.struts.actions.SwitchAction 来实现程序在模块之间的跳转 .

创建独立的 Struts 配置文件

每个 Struts 应用模块必须拥有自己的配置文件。允许创建自己的独立于其他模块的 Action , ActionForm ,异常处理甚至更多。

继续以上面的商店应用程序为例,我们可以创建以下的配置文件:一个文件名为 struts-config-catalog.xml ,包含 catalog (商品目录)、 items( 商品清单 ) 、和其它与库存相关的功能的配置信息;另一个文件名为 struts- config-order.xml, 包含对 order (订单)和 order tracking (订单跟踪)的设置。第三个配置文件是 struts-config.xml, 其中含有属于缺省的应用模块中的一般性的功能。

配置 Web 部署描述符

在 Struts 的早期版本中,我们在 Web.xml 中指定 Struts 配置文件的路径。好在这点没变,有助于向后兼容。但对于多个应用模块,我们需要在 Web 部署描述符中增加新的配置文件的设定。

对于缺省的应用(包括 Struts 的早期版本), Struts framework 在 Web.xml 文件中查找带有 config 的元素 <init-param> ,用于载入 Action mapping 和其它的应用程序设定。作为例子,以下的 XML 片断展现一个典型的 <init-param> 元素:

注:如果在现有的 <init-param> 元素中找不到 "config" 关键字, Struts framework 将缺省地使用 /WEB/struts-config.xml

为了支持多个应用模块 (Struts 1.1 的新特性 ) ,必须增加附加的 <init-param> 元素。与缺省的 <init-param> 元素不同的是,附加的 <init-param> 元素与每个应用模块对应,必须以 config/xxx 的形式命名,其中字符串 xxx 代表该模块唯一的名字。例如,在商店应用程序的例子中, <init-param> 元素可定义如下(注意粗体字部分):

第一个 <init-param> 元素对应缺省的应用模块。第二和第三个元素分别代表非缺省应用模块 catalog 和 order 。

当 Struts 载入应用程序时,它首先载入缺省应用模块的配置文件。然后查找带有字符串 config/xxx 形式的附加的初始化参数。对每个附加的配置文件也进行解析并载入内存。这一步完成后,用户就可以很随意地用 config/ 后面的字符串也就是名字来调用相应的应用模块。

多个应用模块之间调用 Action 类

在为每个应用模块创建独立的配置文件之后,我们就有可能需要调用不同的模块中 Action 。为此必须使用 Struts 框架提供的 SwitchAction 类。 Struts 会自动将应用模块的名字添加到 URL, 就如 Struts 自动添加应用程序的名字加到 URL 一样。应用模块是对框架的一个新的扩充,有助于进行并行的团队开发。如果你的团队很小那就没必要用到这个特性,不必进行模块化。当然,就算是只有一个模块,系统还是一样的运作。

4. 把 JSP 放到 WEB-INF 后以保护 JSP 源代码

为了更好地保护你的 JSP 避免未经授权的访问和窥视, 一个好办法是将页面文件存放在 Web 应用的 WEB-INF 目录下。

通常 JSP 开发人员会把他们的页面文件存放在 Web 应用相应的子目录下。一个典型的商店应用程序的目录结构如图 2 所示。跟 catalog (商品目录)相关的 JSP 被保存在 catalog 子目录下。跟 customer 相关的 JSP ,跟订单相关的 JSP 等都按照这种方法存放。

图 2. 基于不同的功能 JSP 被放置在不同的目录下

按此在新窗口浏览图片

这种方法的问题是这些页面文件容易被偷看到源代码,或被直接调用。某些场合下这可能不是个大问题,可是在特定情形中却可能构成安全隐患。用户可以绕过 Struts 的 controller 直接调用 JSP 同样也是个问题。

为了减少风险,可以把这些页面文件移到 WEB-INF 目录下。基于 Servlet 的声明, WEB-INF 不作为 Web 应用的公共文档树的一部分。因此, WEB-INF 目录下的资源不是为客户直接服务的。我们仍然可以使用 WEB-INF 目录下的 JSP 页面来提供视图给客户,客户却不能直接请求访问 JSP 。

采用前面的例子,图 3 显示将 JSP 页面移到 WEB-INF 目录下后的目录结构

图 3. JSP 存放在 WEB-INF 目录下更为安全

按此在新窗口浏览图片

如果把这些 JSP 页面文件移到 WEB-INF 目录下,在调用页面的时候就必须把 "WEB-INF" 添加到 URL 中。例如,在一个 Struts 配置文件中为一个 logoff action 写一个 Action mapping 。其中 JSP 的路径必须以 "WEB-INF" 开头。如下所示:请注意粗体部分 .

这个方法在任何情况下都不失为 Struts 实践中的一个好方法。是唯一要注意的技巧是你必须把 JSP 和一个 Struts action 联系起来。即使该 Action 只是一个很基本的很简单 JSP ,也总是要调用一个 Action ,再由它调用 JSP 。

最后要说明的是,并不是所有的容器都能支持这个特性。 WebLogic 早期的版本不能解释 Servlet 声明,因此无法提供支持,据报道在新版本中已经改进了。总之使用之前先检查一下你的 Servlet 容器。

5. 使用 Prebuilt Action 类提升开发效率

Struts framework 带有好几个 prebuilt Action 类,使用它们可以大大节省开发时间。其中最有用的是 org.apache.struts.actions.ForwardAction 和 org.apache.struts.actions.DispatchAction.

使用 ForwardAction

在应用程序中,可能会经常出现只要将 Action 对象转发到某个 JSP 的情况。在上一点中曾提到总是由 Action 调用 JSP 是个好习惯。如果我们不必在 Action 中执行任何业务逻辑,却又想遵循从 Action 访问页面的话,就可以使用 ForwardAction ,它可以使你免去创建许多空的 Action 类。运用 ForwardAction 的好处是不必创建自己的 Action 类,你需要做的仅仅是在 Struts 配置文件中配置一个 Action mapping 。

举个例子,假定你有一个 JSP 文件 index.jsp ,而且不能直接调用该页面,必须让程序通过一个 Action 类调用,那么,你可以建立以下的 Action mapping 来实现这一点:

正如你看到的,当 /home 被调用时 , 就会调用 ForwardAction 并把请求转发到 index.jsp 页面 .

再讨论一下不通过一个 Action 类直接转发到某个页面的情况,必须注意我们仍然使用 <action> 元素中的 forward 属性来实现转发的目标。这时 <action> 元素定义如下:

以上两种方法都可以节省你的时间,并有助于减少一个应用所需的文件数。

使用 DispatchAction

DispatchAction 是 Struts 包含的另一个能大量节省开发时间的 Action 类。与其它 Action 类仅提供单个 execute() 方法实现单个业务不同, DispatchAction 允许你在单个 Action 类中编写多个与业务相关的方法。这样可以减少 Action 类的数量,并且把相关的业务方法集合在一起使得维护起来更容易。

要使用 DispatchAction 的功能,需要自己创建一个类,通过继承抽象的 DispatchAction 得到。对每个要提供的业务方法必须有特定的方法 signature 。例如,我们想要提供一个方法来实现对购物车添加商品清单,创建了一个类 ShoppingCartDispatchAction 提供以下的方法:

那么,这个类很可能还需要一个 deleteItem() 方法从客户的购物车中删除商品清单,还有 clearCart() 方法清除购物车等等。这时我们就可以把这些方法集合在单个 Action 类,不用为每个方法都提供一个 Action 类。

在调用 ShoppingCartDispatchAction 里的某个方法时,只需在 URL 中提供方法名作为参数值。就是说,调用 addItem() 方法的 URL 看起来可能类似于:

http://myhost/storefront/action/cart?method=addItem

其中 method 参数指定 ShoppingCartDispatchAction 中要调用的方法。参数的名称可以任意配置,这里使用的 "method" 只是一个例子。参数的名称可以在 Struts 配置文件中自行设定。

6. 使用动态 ActionForm

在 Struts framework 中, ActionForm 对象用来包装 HTML 表格数据(包括请求),并返回返回动态显示给用户的数据。它们必须是完全的 JavaBean ,并继承 .Struts  里面的 ActionForm 类,同时,用户可以有选择地覆盖两个缺省方法。

该特性能节省很多时间,因为它可以协助进行自动的表现层的验证。 ActionForm 的唯一缺点是必须为不同的 HTML 表格生成多个 ActionForm 类以保存数据。例如,如果有一个页面含有用户的注册信息,另一个页面则含有用户的介绍人的信息,那么就需要有两个不同的 ActionForm 类。这在大的应用系统中就会导致过多的 ActionForm 类。 Struts 1.1 对此做出了很好的改进,引入了动态 ActionForm 类概念

通过 Struts framework 中的 DynaActionForm 类及其子类可以实现动态的 ActionForm ,动态的 ActionForm 允许你通过 Struts 的配置文件完成 ActionForm 的全部配置;再也没有必要在应用程序中创建具体的 ActionForm 类。具体配置方法是:在 Struts 的配置文件通过增加一个 <form-bean> 元素,将 type 属性设定成 DynaActionForm 或它的某个子类的全名。下面的例子创建了一个动态的 ActionForm 名为 logonForm ,它包含两个实例变量: username 和 password.

动态的 ActionForm 可以用于 Action 类和 JSP ,使用方法跟普通的 ActionForm 相同,只有一个小差别。如果使用普通的 ActionForm 对象则需要提供 get 和 set 方法取得和设置数据。以上面的例子而言,我们需要提供 getUsername() 和 setUsername() 方法取得和设置 username 变量,同样地有一对方法用于取得和设置 password 变量 .

这里我们使用的是 DynaActionForm ,它将变量保存在一个 Map 类对象中,所以必须使用 DynaActionForm 类中的 get(name) 和 set(name) 方法,其中参数 name 是要访问的实例变量名。例如要访问 DynaActionForm 中 username 的值,可以采用类似的代码:

String username = (String)form.get("username");

由于值存放在一个 Map 对象,所以要记得对 get() 方法返回的 Object 对象做强制性类型转换。

DynaActionForm 有好几个很有用的子类。其中最重要的是 DynaValidatorForm ,这个动态的 ActionForm 和 Validator 一起利用公共的 Validator 包来提供自动验证。这个特性使你得以在程序代码之外指定验证规则。将两个特性结合使用对开发人员来说将非常有吸引力。

7. 使用可视化工具

自从 Struts 1.0 分布以来,就出现了不少可视化工具用于协助创建,修改和维护 Struts 的配置文件。配置文件本身是基于 XML 格式,在大中型的开发应用中会增大变得很笨拙。为了更方便的管理这些文件,一旦文件大到你无法一目了然的时候,建议试着采用其中的一种 GUI 工具协助开发。商业性的和开放源代码的工具都有不少,表 1 列出了可用的工具和其相关链接,从那里可以获取更多信息。

表 1. Struts GUI 工具
应用程序 性质 网址
Adalon 商业软件 http://www.synthis.com/products/adalon
Easy Struts 开放源码 http://easystruts.sourceforge.net/
Struts Console 免费 http://www.jamesholmes.com/struts/console
JForms 商业软件 http://www.solanasoft.com/
Camino 商业软件 http://www.scioworks.com/scioworks_camino.html
Struts Builder 开放源码 http://sourceforge.net/projects/rivernorth/
StrutsGUI 免费 http://www.alien-factory.co.uk/struts/struts-index.html

相关资源

要获取更为全面的 Struts GUI 工具列表 ( 包括免费的和商业性的 ), 请访问 Struts resource page.
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值