RequestProcessor及其在struts-config.xml中的配置
<controller processorClass="cn.ourbooks.common.MyRequestProcessor" />
通常来讲,好象不常用到。
但如果想从源头抓头对Web层的控制,就非得做一个RequestProcessor的过滤器。
在这里说一个最明显示的例子:
在使用Struts的过程中,对Session Timeout或者客户是否登录的判断往往是放到一个Action基类(继承于Struts的Action)中处理(反正以前我们的系统就是这样的),放到Action基类里的意图很明显是不需要在jsp或每个小处理的Action中处理这种共性的事务。
但是在测试过程中发现,Struts中Form的validate在验证出错后,不会走Action而是直接mapping到错误页面了。这样,我们的Session Timeout的判断机制就不管用了。
这种情况下有时会给客户一个很不友好的感觉。客户输入了很多数据,提示有错(这时有可能已经Session Timeout,但系统没有觉查),改完了,再提交,如果验证通过,此时有可能会告诉客户,您没有登录或是Session Timeout。对于客户来讲大有捶胸顿足的气愤,要提示Session Timeout早提示,偏偏三番五次改正确了,却又提示Session Timeout。
此时怎么办呢?
Struts在诸类框架中的老大地位,决定了其非常强的扩展功能。
我们可以配置自己的RequestProcessor,比如MyRequestProcessor。
重置其中的processValidate方法,在调用父类的processValidate方法之前进行Session Timeout的验证,如果验证不过,就可以转移到公共Session Timeout的页面了,否则,就可以调用父类的processValidate方法。
写完MyRequestProcessor类后,还需要在struts-config.xml中配置一下,格式如下:
<controller processorClass="cn.ourbooks.common.MyRequestProcessor" />
这样,在调用ActionForm的validate方法之前就进行了Session Timeout的验证,使系统对Session Timeout作到有效的把握。
以上只是例一,再谈个例二,例二是个补救的例子。
Struts的RequestProcessor中会维护一个action Map,里面放着用过的Action,在一个请求来了之后,先判断这个请求的action在action Map中是否存在,如果不存在就创建一个,并加到action Map中,如果已经存在,就不创建新的了,取出来用就是了。
默认情况下,Tomcat(AP Searver)中也只是维护着一个Action Servlet,这一连串下来,有一个很关键的问题,我们需要注意,就是在Action中不能声明属性,如果声明了,这个属性是所有请求共享的。举例说明就是,假如在Action中声明了属性,并定义其默认值为123,第一个访问者(请求)将这个属性的值改为了abc,那么第二个访问者(请求)取得这个属性的值时,将得到abc,而不是123。
哈哈,如果有个很糟糕的情况,你的系统已经做的很大了,而且在Action中也定了好多属性,怎么办呢?难道改造所有的Action,那代价太大了。
好了,还是RequestProcessor,我们可以在其子类MyRequestProcessor(也就是上例我们自己做的那个)中,重置processActionCreate方法,大家可以查一下Struts关于RequestProcessor类的源码,找到processActionCreate方法,原封不动拷到MyRequestProcessor中,注释下面几行:
instance = (Action) actions.get(className);
if (instance != null) {
if (log.isTraceEnabled()) {
log.trace(" Returning existing Action instance");
}
return (instance);
}
就实现了每个请求,都创建一个新的Action实例。这样,即使在Action中声明了属性,在多请求的情况下,也互不影响(虽然效率上可能低点,但是总比项目快结束了,再返工的好)。