编程时要注意细节
随着Struts2与WebWork的联袂,Struts1已经不再是人们追捧的对象了。不过,若要快速开发一个小型的Web应用,我还是推荐各位使用Struts1。因为无论是在开发速度、运行速度、资料、成熟度等各个方面,目前来看Struts1还是有自身的优势的。另外一个优势在于,几乎所有的j2ee开发者,或多或少都有Struts1的开发经验,有了这样的经验,在实现小型Web应用时,会更敏捷(敏捷不光是一味地追求开发速度,还要能够快速地应对变化。这不光是程序设计方面的问题,若你对所使用的框架非常了解,无疑将会对整个项目起来很积极的作用)。
Tycho第一个版本的显示层就是使用的 Struts1 。虽然对 Struts 的学习和应用已经有些年头了,但在开发过程中,由于疏忽一个小细节操作不当出现许多问题。
我所说的小细节,主要是在配置 struts-config.xml 文件时,代码前后矛盾引起的死循环提交。首先我们先来回顾一下Struts应用的传统的编写方式。
我们知道,利用 Struts 的 DispatchAction 可以将程序提交到参数所指定的 action 的方法中。例如:
index.do?method=go(URL地址)
这个地址就调用了action mapping为index的action的go方法。让我们来回想一下 DispatchAction的 分发机制:DispatchAction 就是在 struts-config 中用 parameter 参数配置一个表单字段名,这个字段的值就是最终替代execute被调用的方法. 例如:parameter="method" 而 request.getParameter("method")="save",其中"save"就是MethodName。struts的请求将根据 parameter 被分发到"save"或者"edit"或者什么。但是有一点,save()或者edit()等方法的声明和 execute 必须一模一样。ActionServlet会根据配置文件中 parameter 的配置取对应的参数做为要调用的方法进行调用(除非 action bean 中含有 execute 方法)。在action执行完任务后,利用 mapping.findForward 返回配置文件设置的对应的页面或其它 action bean。值得注意的是,mapping.findForward 返回的是一个 action bean 时,需要指定所要调用的方法。例如:
大家都知道,问号后面跟着的是参数,是放在request中保存的,那么,如果没有指定方法将前一次的 method 参数覆盖,Struts 则默认将刚才提交进来的method作为其要调用的方法来处理,这样就很可能造成死循环提交。例如下面这组程序以及它的配置:
public class AAction extends DispatchAction {
public ActionForward go(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
return mapping.findForward("success");
}
}
AAction类继承了DispatchAction类,并在其中定义了方法go,该方法没有做任何的事情,只是返回配置文件中 success 所指向的那个地址。
public class BAction extends DispatchAction {
public ActionForward go(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
return mapping.findForward("success");
}
}
同 AAction 类一样,BAction 同样也继承了DispatchAction类。其中定义了 go 方法。该方法返回了配置文件中 success 所指向的那个地址。
##这里没有指定其方法且转发到BAction中
##这里没有指定其方法且转发到Aaction中
struts-config.xml中对 AAction 和 BAction 分别进行了配置,在 AAction 的 success forward 中,将该地址转发到 BAction 。而 BAction 的 success forward 将该地址转发到 AAction。问题来了,当我们访问 aaction.do?method=go 这个地址时,Struts 会根据配置调用 AAction 的 go 方法,该方法返回 success ,紧接着 Struts 会根据 forward 中的配置将地址转发到 BAction 。细心的朋友一定注意到了,在 forward 中,我们仅仅将地址转发到 baction.do ,按正常情况来讲,这时 Struts 会去调用 BAction 的 execute 方法,但实际上,它却调用了 BAction 的 go 方法。正如我们刚才所说,在调用 AAction 的 go 方法的时候,go 参数会被放在 request 中保存,而 Struts 根据配置调用 BAction 时,这一次的会话并没有结束,也就是说参数 go 仍然保存在 request 中,形成了这样的地址: baction.do?method=go 。这时,BAction 的 go 方法自然被调用。
更糟的还不止如此,BAction 的 go 方法执行完后,又被被转发到 AAction ,再次形成了 aaction.do?method=go 的地址,如此反复循环下去。
总结:用 Struts1 开发小型的 Web 应用是非常快捷的,很多开发人员都有 Struts1 的相关经验,这使得开发能够更加敏捷。但是,Struts 的细节仍然不能被忽视,在配置 forward 时,尤其要仔细,配置的地址都应该是实际存在的,不要因为 Struts 提供了可以自定义方法和默认 execute 方法的便利而出现上面的问题。


















