Struts2 自定义拦截器栈后无法得到表单参数之解决办法

我自定义了一个拦截器,目的是在action执行之前像ValueStack中设置一些属性,代码是这样的:

[java:nogutter] view plain copy
  1. HttpServletRequestrequest=(HttpServletRequest)ActionContext.getContext().get(StrutsStatics.HTTP_REQUEST);
  2. OgnlValueStackstack=(OgnlValueStack)request.getAttribute("struts.valueStack");
  3. /**
  4. *Settheproperties
  5. */
  6. List<Category>cityList=systemService.getCategorySortList("city");
  7. stack.set("cityList",cityList);
  8. EhcacheVindicatorProxyproxy=newEhcacheVindicatorProxy("menu");
  9. List<FrontMenu>frontMenuList=(List)proxy.get(FrontMenu.class,"frontmenus","menus.xml");
  10. stack.set("frontMenuList",frontMenuList);
  11. returninvocation.invoke();

 

struts.xml中是这样配置的:

 

<!--引用默认拦截器-->
<interceptor-ref name="properties" />
<interceptor-ref name="defaultStack" />

 

 

这样配置以后确实可以达到我要的效果,但是问题却出来了,这样配置以后表单参数无法获得,全都是默认为空。我们来看下面一段描述:

 

众所周知,Struts2的Action类通过属性可以获得所有相关的值,如请求参数、Action配置参数、向其他Action传送属性值(通过chain结果)等等。要获得这些参数值,我们要做的唯一一件事就是在Action类中声明与参数同名的属性,在Struts2调用Action类的Action方法(默认是execute)方法之前,就会为相应的Action属性赋值。

要完成这个功能,有很大程度上,Struts 2要依赖与ValueStack对象。这个对象贯穿整个Action的生命周期(每个Action类的对象实例会拥有一个ValueStack对象)。当Struts 2接收到一个action的请求后,会先建立Action类的对象实例,但不会调用Action方法,而是先将Action类的相应属性放到ValueStack对象的顶层节点(ValueStack对象相当于一个栈).只是所有的属性值都是默认的值,如String类型的属性值为null,int类型的属性值为0等。

在处理完上述工作后,Struts 2就会调用拦截器链中的拦截器,当调用完所有的拦截器后,最后会调用Action类的Action方法,在调用Action方法之前,会将ValueStack对象顶层节点中的属性值赋给Action类中相应的属性。大家要注意,在这里就给我们带来了很大的灵活性。也就是说,在Struts 2调用拦截器的过程中,可以改变ValueStack对象中属性的值,当改变某个属性值后,Action类的相应属性值就会变成在拦截器中最后改变该属性的这个值。

从上面的描述很容易知道,在Struts 2的Action类可以获得与属性同名的参数值就是通过不同的拦截器来处理的,如获得请求参数的拦截器是params,获得Action的配置参数的拦截器是staticParams等。在这些拦截器内部读取相应的值,并更新ValueStack对象顶层节点的相应属性的值。而ValueStack对象就像一个传送带,将属性值从一个拦截器传到另一个拦截器(当然,在这期间,属性值可能改变),最后会传到Action对象,并将ValueStack对象中的属性的值终值赋给Action类的相应属性。

 

从上面的描述可以看出,当在拦截器中进行ValueStack传递的时候,属性值是可能改变,分析原因我们大概可以知道是这段代码:

 

[java:nogutter] view plain copy
  1. /**
  2. *Settheproperties
  3. */
  4. List<Category>cityList=systemService.getCategorySortList("city");
  5. stack.set("cityList",cityList);
  6. EhcacheVindicatorProxyproxy=newEhcacheVindicatorProxy("menu");
  7. List<FrontMenu>frontMenuList=(List)proxy.get(FrontMenu.class,"frontmenus","menus.xml");
  8. stack.set("frontMenuList",frontMenuList);

 

影响了后续defaultStack对属性值的设置,所以我们应该将这段代码最后执行,那么怎么最后执行了,这里就要知道拦截器栈的执行顺序的知识了,在这里就不讲了,修改后是遮掩的:

 

 

[java:nogutter] view plain copy
  1. HttpServletRequestrequest=(HttpServletRequest)ActionContext.getContext().get(StrutsStatics.HTTP_REQUEST);
  2. OgnlValueStackstack=(OgnlValueStack)request.getAttribute("struts.valueStack");
  3. Stringresult=invocation.invoke();
  4. /**
  5. *Settheproperties
  6. */
  7. List<Category>cityList=systemService.getCategorySortList("city");
  8. stack.set("cityList",cityList);
  9. EhcacheVindicatorProxyproxy=newEhcacheVindicatorProxy("menu");
  10. List<FrontMenu>frontMenuList=(List)proxy.get(FrontMenu.class,"frontmenus","menus.xml");
  11. stack.set("frontMenuList",frontMenuList);
  12. returnresult;

 

这样就可以保证不会干扰params之类的默认拦截器的执行。

 

这里要注意的是拦截器的执行顺序,如果设成这样:

 

[java:nogutter] view plain copy
  1. <!--引用默认拦截器-->
  2. <interceptor-refname="defaultStack"/>
  3. <interceptor-refname="properties"/>

 

我们要设的值不会设置成功

 

当然在这里具体的原因我没有分析,只大略讲了一下,如果你有更好的解释,请联系我874904507

猜你喜欢

转载自tydldd.iteye.com/blog/1720185