清单6中的代码与清单4中的很相像,唯一区别是用ActionMapping findForward替代了RequestDispatcher forward。清单6中,如果在HttpSession中未找到username字符串,ActionMapping对象将找到名为sessionEnded的forward元素并跳转到对应的path。如果找到了,子类通过实现executeAction()方法,将执行他们自己的业务逻辑。因此,在struts-web.xml配置文件中为所有继承自Action基类的子类声明个一名为sessionEnded的forward元素并将其指向login.jsp是至关重要的。清单7以secure1 action阐明了这样一个声明:
清单7
|
继承自BaseAction类的子类Secure1Action实现了executeAction()方法而不是覆盖它。Secure1Action类不需要执行任何退出代码,如清单8:
清单8
|
上面的解决方案是如此的优雅有效,它仅仅只需要定义一个基类而不需要额外的代码工作。将通用的行为方法写成一个继承StrutsAction的基类是者的推荐的,而且这是许多Struts项目的共同经验。
十一. 局限性
上述解决方案对JSP或基于Struts的Web应用都是非常简单而实用的,但它还是有某些局限。在我看来,这些局限并不是至关紧要的。
• 通过取消与浏览器后退按钮有关的缓存机制,一旦用户离开页面而没有对数据进行提交,那么页面将会丢失所有输入的数据。即使点击浏览器的后退按钮返回到刚才的页面也无济于事,因为浏览器会从服务器获取新的空白页面显示出来。一种可能的方法并不是阻止这些JSP页面包含数据数据表格。在基于JSP的解决方案当中,那些JSP页面可以删除在清单4中的代码。在基于Struts的解决方案当中,Action类需要继承自Struts的Action类而非BaseAction类。
• 上面讲述的方法在Opera浏览器中不能工作。事实上没有适用于Opera浏览器的解决方案,因为Opera浏览器与2616 Hypertext Transfer Protocol—HTTP/1.1紧密相关。Section 13.13 of RFC 2616 states:
User agents often have history mechanisms, such as "Back" buttons and history lists, which can be used to redisplay an entity retrieved earlier in a session.
History mechanisms and caches are different. In particular history mechanisms SHOULD NOT try to show a semantically transparent view of the current state of a resource. Rather, a history mechanism is meant to show exactly what the user saw at the time when the resource was retrieved.
幸运的是,使用微软的IE和基于Mozilla的浏览器用户多余Opera浏览器。上面讲述的解决方案对大多数用户来说还是有帮助的。另外,无论是否使用上述的解决方案,Opera浏览器仍然存在用户退出问题,就Opera来说没有任何改变。然而,正如RFC2616中所说,通过像上面一样设置头文件指令,当用户点击一个链接时,Opera浏览器不会从缓存中获取页面。
十二. 结论
这篇文章讲述了处理退出问题的解决方案,尽管方案简单的令人惊讶,但在所有情况下都能有效地工作。无论是对JSP还是Struts,所要做的不过是写一段不超过50行的代码以及一个记录用户最后登陆时间的方法。在有密码保护的Web应用中使用这些方案能够确保在任何情况下用户的私人数据不致泄露,同时,也能增加用户的经验。

