WEB开发网
开发学院WEB开发Jsp Struts教程-Struts的几个精细之处 阅读

Struts教程-Struts的几个精细之处

 2008-01-05 09:43:26 来源:WEB开发网   
核心提示:最近在网上看到一篇N. Alex Rupp写的“Beyond MVC: A New Look at the Servlet InfrastrUCture”文章,意思大致是说MVC被Struts等框架错误地应用到了Servlet架构中,Struts教程-Struts的几个精细之处,我想只有对Struts有足够的了解再加上

最近在网上看到一篇N. Alex Rupp写的“Beyond MVC: A New Look at the Servlet InfrastrUCture”文章,意思大致是说MVC被Struts等框架错误地应用到了Servlet架构中。我想只有对Struts有足够的了解再加上在MVC方面有足够深的功力,才敢发此言论,不是经常听人说:最熟悉自己的人是你的敌人。本人功力尚浅,没有引领风潮的能力,而且生活还得继续,只能先来熟悉熟悉Struts。

申明: 强烈建议在阅读本文之前先阅读一下N. Alex Rupp老兄的文章,假如你赞同他的看法,可能你会觉得研究Struts就没什么意义了。

说明:本文所讲的Struts知识基于Struts 1.1版本,除非非凡说明,本文中的Struts都特指Struts 1.1这个版本。

精细之处一:“利用Token解决重复提交”背后的前提

我们知道,可以利用同步令牌(Token)机制来解决Web应用中重复提交的问题,Struts也给出了一个参考实现。服务器端在处理到达的请求之前,会将请求中包含的令牌值与保存在当前用户会话中的令牌值进行比较,看是否匹配。在处理完该请求后,且在答复发送给客户端之前,将会产生一个新的令牌,该令牌除传给客户端以外,也会将用户会话中保存的旧的令牌进行替换。这样假如用户回退到刚才的提交页面并再次提交的话,客户端传过来的令牌就和服务器端的令牌不一致,从而有效地防止了重复提交的发生。对应于这段描述,你可能会在你的Action子类中有这么一段代码:

if (isTokenValid(request, true)) {
	// your code here
return mapping.findForward("success");
} else {
saveToken(request);
return mapping.findForward("submitagain");
}

其中isTokenValid()和saveToken()都是org.apache.struts.action.Action类中的方法,而具体的Token处理逻辑都在org.apache.struts.util.TokenPRocessor类中。Struts中是根据用户会话ID和当前系统时间来生成一个唯一(对于每个会话)令牌的,具体实现可以参考TokenProcessor类中的generateToken()方法。

不知道大家有没有注重到这样一个问题,因为Struts是将Token保存在session的一个属性中,也就是说对于每个会话服务器端只保存而且只能保存一个最新Token值。对于这一点,我的同事就提出了疑问:那假如我在同一个会话中打开两个页面,那么后提交的那个页面肯定不能提交成功了。他还给出了一个实际的例子:比如现在需要把两个客户A和B的地址都改为某个值,那用户就可能同时打开两个页面,修改A,修改B,提交A,提交B,按照Struts中的处理逻辑,B的修改提交就肯定不能成功,但是这个提交操作对于用户来说并不存在操作不正确的地方。

在这里,可能有人要问:怎么可能在同一个会话中打开两个页面呢?重新打开一个IE浏览器不是重新开始了一个会话吗?不错,这种情况下是两个会话,不存在任何问题。但是,你还可以通过菜单“文件”-“新建”-“窗口”(或者快捷键Ctrl+N)来复制当前窗口,这个时候你会发现该页面与原有页面同处在一个会话当中。其实,能够发现这个问题得归功于我的那位同事对IE习惯性的操作方法。

这下我的那位同事不满足啦,他于是开始动手修改Struts中的实现方式,让每个页面(至少某类页面)在服务器端都保存有一个唯一的Token值。这样,前面所讲的客户A,B同时修改的限制就不存在了。但是不久,我的那位同事就开始意识到他正在走向一条危险的道路。首先,假如每个页面都在服务器端保存一个Token值,则服务器端保存的数据量将越来越大。而且,假如考虑这种同一个会话中打开多个页面的情况的话,就似乎打开了潘多拉魔盒,将会给自己带来无穷无尽的麻烦。比如,首先打开页面P1,然后利用Ctrl+N得到页面P2,P1提交,P2提交,目前为止一切正常。但是假如此时,在P1,P2中点击“后退”按钮,然后再提交P1, P2呢,情况会是怎样?假如在P2中提交完后执行其它操作,而在P1中回退后提交,情况又是怎么样呢?假如有P1,P2,P3,那情况又是如何呢?太复杂啦!我想你也会和我们有同感,你需要考虑许多种可能的组合,而且有的时候结果并不是你想象中的那样简单。

此路不通,还得回来看看Struts。其实经过以上一番折腾,我们可以发现在Struts中的Token机制背后隐藏着这样一个前提:不答应你(客户端)在同一会话中打开多个页面。注重是同一会话,假如打开两个IE浏览器,那已经是两个会话啦,不受该限制。其实,这个看似不合理的规定却自有其道理:一是它极大地简化了Token的实现,二个这种限定也符合大部分人的使用习惯。

精细之处二:页面流转控制中的职责分配

我们知道,Struts的执行过程大致如下:首先,控制器接收到客户端请求,将这些请求映射至相应的Action,并调用Action的execute方法,这中间可能还涉及到ActionForm的创建和填充。Action的execute方法执行完以后,返回一个ActionForward对象,控制器根据该ActionForward对象将请求转发至下一个Action或jsp。最后,产生视图响应客户。在大的层面上,Struts是采用了MVC这种架构,没什么非凡之处。但从一些小的地方,我们还是可以看出Craig R. McClanahan老兄的一些考虑。我们看到Action与控制器之间传递的是ActionForward对象,由于Action的execute方法要求返回一个ActionForward对象,所以你会经常在Action子类中看到如下语句:

Tags:Struts 教程 Struts

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接