(作者Chuck Cavaness 编译 邱文宇)
编者按当作者 Chuck Cavaness(着有《Programming Jakarta Struts》一书)所在的网络公司决定采用Struts框架之后Chuck曾经花费了好几个月来研究如何用它来构建公司的应用系统本文叙述的正是作者在运用Struts过程中来之不易的若干经验和心得如果你是个负责通过jsp和servlet开发Web应用的Java程序员并且也正在考虑采用基于Struts的构建方法的话那么你会在这里发现很多颇有见地同时也很有价值的信息
只在必要的时候才考虑扩展Struts框架
一个好的framework有很多优点首先它必须能够满足用户的可预见的需求为此 Struts为Web 应用提供了一个通用的架构这样开发人员可以把精力集中在如何解决实际业务问题上其次一个好的framework还必须能够在适当的地方提供扩展接口以便应用程序能扩展该框架来更好的适应使用者的实际需要
如果Struts framework在任何场合任何项目中都能很好的满足需求那真是太棒了但是实际上没有一个框架声称能做到这一点一定会有一些特定的应用需求是框架的开发者们无法预见到的因此最好的办法就是提供足够的扩展接口使得开发工程师能够调整struts来更好的符合他们的特殊要求
在Struts framework中有很多地方可供扩展和定制几乎所有的配置类都能被替换为某个用户定制的版本这只要简单的修改一下Struts的配置文件就可以做到
其他组件如ActionServlet和 RequestProcessor 也能用自定义的版本代替 甚至连Struts 里才有的新特性也是按照扩展的原则来设计的例如在异常处理机制中就允许用户定制异常处理的句柄以便更好的对应用系统发生的错误做出响应
作为框架的这种可调整特性在它更适合你的应用的同时也在很大的程度上影响了项目开发的效果首先由于您的应用是基于一个现有的成熟的稳定的framework如Struts测试过程中发现的错误数量将会大大减少同时也能缩短开发时间和减少资源的投入因为你不再需要投入开发力量用于编写基础框架的代码了
然而 实现更多的功能是要花费更大的代价的我们必须小心避免不必要的滥用扩展性能 Struts是由核心包加上很多工具包构成的它们已经提供了很多已经实现的功能因此不要盲目的扩展Struts框架要先确定能不能采用其他方法使用现有的功能来实现 在决定编写扩展代码前务必要确认Struts的确没有实现你要的功能否则重复的功能会导致混乱将来还得花费额外的精力清除它
使用异常处理声明
要定义应用程序的逻辑流程成熟的经验是推荐在代码之外用配置的方法来实现而不是写死在程序代码中的在JEE中这样的例子比比皆是从实现EJB的安全性和事务性行为到描述JMS消息和目的地之间的关系很多运行时的处理流程都是可以在程序之外定义的
Struts 创建者从一开始就采用这种方法通过配置Struts的配置文件来定制应用系统运行时的各个方面这一点在版本的新特性上得到延续包括新的异常处理功能在Struts framework以前的版本中开发人员不得不自己处理Struts应用中发生的错误情况在最新的版本中情况大大的改观了Struts Framework提供了内置的一个称为 ExceptionHandler 的类 用于系统缺省处理action类运行中产生的错误这也是在上一个技巧中我们提到的framework许多可扩展接口之一
Struts缺省的 ExceptionHandler类会生成一个ActionError对象并保存在适当的范围(scope)对象中这样就允许JSP页面使用错误类来提醒用户出现什么问题如果你认为这不能满足你的需求那么可以很方便的实现你自己的ExcepionHandler类
具体定制异常处理的方法和机制
要定制自己的异常处理机制第一步是继承orgapachestrutsactionExceptionHandler类这个类有个方法可以覆盖一个是excute()另外一个是storeException() 在多数情况下只需要覆盖其中的excute()方法下面是ExceptionHandler类的excute()方法声明
正如你看到的该方法有好几个参数其中包括原始的异常方法返回一个ActionForward对象用于异常处理结束后将controller类带到请求必须转发的地方去
当然您可以实现任何处理但一般而言我们必须检查抛出的异常并针对该类型的异常进行特定的处理缺省的系统的异常处理功能是创建一个出错信息同时把请求转发到配置文件中指定的地方去 定制异常处理的一个常见的例子是处理嵌套异常假设该异常包含有嵌套异常这些嵌套异常又包含了其他异常因此我们必须覆盖原来的execute()方法对每个异常编写出错信息
一旦你创建了自己的ExceptionHandler 类就应该在Struts配置文件中的部分声明这个类以便让Struts知道改用你自定义的异常处理取代缺省的异常处理
可以配置你自己的ExceptionHandler 类是用于Action Mapping特定的部分还是所有的Action对象如果是用于Action Mapping特定的部分就在元素中配置如果想让这个类可用于所有的Action对象可以在 元素中指定例如假设我们创建了异常处理类CustomizedExceptionHandler用于所有的Action类 元素定义如下所示在元素中可以对很多属性进行设置在本文中最重要的属性莫过于handler属性 handler属性的值就是自定义的继承了ExceptionHandler类的子类的全名 假如该属性没有定义Struts会采用自己的缺省值当然其他的属性也很重要但如果想覆盖缺省的异常处理的话handler无疑是最重要的属性
最后必须指出的一点是你可以有不同的异常处理类来处理不同的异常在上面的例子中CustomizedExceptionHandler用来处理任何javalangException的子类 其实你也可以定义多个异常处理类每一个专门处理不同的异常树下面的XML片断解释了如何配置以实现这一点
在这里一旦有异常抛出struts framework将试图在配置文件中找到ExceptionHandler如果没有找到那么struts将沿着该异常的父类链一层层往上找直到发现匹配的为止因此我们可以定义一个层次型的异常处理关系结构在配置文件中已经体现了这一点
使用应用模块(Application Modules)
Struts 的一个新特性是应用模块的概念应用模块允许将单个Struts应用划分成几个模块每个模块有自己的Struts配置文件JSP页面Action等等这个新特性是为了解决大中型的开发队伍抱怨最多的一个问题即为了更好的支持并行开发允许多个配置文件而不是单个配置文件
注在早期的beta版本中该特性被称为子应用(subapplications)最近的改名目的是为了更多地反映它们在逻辑上的分工
显然当很多开发人员一起参加一个项目时单个的Struts配置文件很容易引起资源沖突应用模块允许Struts按照功能要求进行划分许多情况已经证明这样更贴近实际例如假设我们要开发一个典型的商店应用程序可以将组成部分划分成模块比如catalog(商品目录) customer(顾客) customer service(顾客服务) order(订单)等每个模块可以分布到不同的目录下这样各部分的资源很容易定位有助于开发和部署图 显示了该应用的目录结构
图 一个典型的商店应用程序的目录结构
注如果你无需将项目划分成多个模块Struts框架支持一个缺省的应用模块这就使得应用程序也可以在版本下创建具有可移植性因为应用程序会自动作为缺省的应用模块
为了使用多应用模块功能必须执行以下几个准备步骤
; 为每个应用模块创建独立的Struts配置文件
; 配置Web 部署描述符 Webxml文件
; 使用orgapachestrutsactionsSwitchAction 来实现程序在模块之间的跳转
创建独立的Struts配置文件
每个Struts应用模块必须拥有自己的配置文件允许创建自己的独立于其他模块的ActionActionForm异常处理甚至更多
继续以上面的商店应用程序为例我们可以创建以下的配置文件一个文件名为strutsconfigcatalogxml包含catalog(商品目录)items(商品清单)和其它与库存相关的功能的配置信息另一个文件名为struts configorderxml 包含对order(订单)和order tracking(订单跟蹤)的设置第三个配置文件是strutsconfigxml其中含有属于缺省的应用模块中的一般性的功能
配置Web部署描述符
在Struts的早期版本中我们在Webxml中指定Struts配置文件的路径好在这点没变有助于向后兼容但对于多个应用模块我们需要在Web部署描述符中增加新的配置文件的设定
对于缺省的应用(包括Struts的早期版本)Struts framework 在Webxml文件中查找带有config的元素用于载入Action mapping 和其它的应用程序设定作为例子以下的XML片断展现一个典型的元素注如果在现有的元素中找不到config关键字Struts framework将缺省地使用/WEB/strutsconfigxml为了支持多个应用模块(Struts 的新特性)必须增加附加的元素与缺省的元素不同的是附加的元素与每个应用模块对应必须以config/xxx的形式命名其中字符串xxx代表该模块唯一的名字例如在商店应用程序的例子中元素可定义如下(注意粗体字部分)第一个 元素对应缺省的应用模块第二和第三个元素分别代表非缺省应用模块catalog 和 order当Struts载入应用程序时它首先载入缺省应用模块的配置文件然后查找带有字符串config/xxx 形式的附加的初始化参数对每个附加的配置文件也进行