一,要配置struts.xml文件。
<struts> <package name="methodFilter" extends="struts-default"> <interceptors> <interceptor name="myInterceptor11" class="com.jadyer.interceptor.MyInterceptor11"> <param name="hello">world</param> </interceptor> <!-- <param name="hello">world</param>表示为拦截器增加一个名为hello值为world的属性 --> <!-- 但是这里也只是为hello赋了初值为world。如若在下面的<action/>中配置使用该拦截器的时候 --> <!-- 增加了<param name="hello">welcome</param>,则最后拦截器类中hello属性值即为welcome --> <interceptor name="myInterceptor33" class="com.jadyer.interceptor.MyInterceptor33"> <param name="includeMethods">test,abc</param> </interceptor> </interceptors> <action name="methodFilter" class="com.jadyer.action.MethodFilterAction" method="test"> <result name="success">/methodFilterResult.jsp</result> <interceptor-ref name="defaultStack"/> <interceptor-ref name="myInterceptor11"/> <interceptor-ref name="myInterceptor33"> <param name="includeMethods">abc</param> </interceptor-ref> </action> </package> </struts>
要点:1,默认情况下,拦截器会拦截Action中的所有方法,这里不包括setter或getter方法。这时就可以使用方法过滤拦截器来拦截指定的方法,这是一种更加细化的拦截器的配置方式。它可以细化到拦截具体的某个方法,而不是拦截某个Action,因为拦截Action是一种粗粒度的实现方式。
2,使用includeMethods指明拦截器所要拦截的方法,使用excludeMethods指明拦截器不再拦截的方法。这里excludeMethods和includeMethods是在MethodFilterInterceptor类中定义的成员变量。
3,只要includeMethods进来的方法就一定会被拦截,而不管是否已经把它excludeMethods在外了。也就是说,includeMethods的优先级要高于excludeMethods!
4,也可以使用<param name="includeMethods" />在上面定义拦截器的时候指定全局性过滤的方法。区别就是对方法的过滤有全局性和局部性区分,而当发生冲突时,则依照“就近原则”以局部性的配置为准。(所谓的发生冲突,指的是类似于全局中有一个includeMethods配置,而局部中也有一个includeMethods配置!)
5,还有一种情况——假设全局性过滤定义为<param name="includeMethods">test</param>,而在局部性过滤中定义为<param name="excludeMethods">test</param>。这种情况下,前者将生效,即拦截Action中的test()方法。因为全局中配置的是拦截,局部中配置的是不拦截,二者并没有发生冲突,所以仍是以includeMethods优先级高。(可以认为在局部的配置中,已经隐含地把<param name="includeMethods">test</param>继承过来了!)
6,这里衡量的所谓拦截到与否,主要可以通过查看控制台输出的语句,以判断是否执行到该拦截器内部。
二,然后写实现了Interceptor接口的自定义拦截器MyInterceptor11.java。
package com.jadyer.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
/**
* 实现Interceptor接口的自定义拦截器
* @see 【这种方式不太常用】
*/
@SuppressWarnings("serial")
public class MyInterceptor11 implements Interceptor {
//这里的属性名要与struts.xml配置的<param name=""/>中的name值相同
//然后Struts2会自动将struts.xml中配置的world值赋值到这里的hello属性中
//当然,前提是要提供setter和getter方法,只要符合JavaBean的要求即可
private String hello;
public String getHello() {
return hello;
}
public void setHello(String hello) {
this.hello = hello;
}
/**
* 初始化时执行的方法
*/
public void init() {
System.out.println("------MyInterceptor11 init method invoked------");
System.out.println(hello);
}
/**
* 销毁时执行的方法
*/
public void destroy() {
System.out.println("------MyInterceptor11 destroy method invoked------");
}
//每执行一次action请求,这里的intercept()方法都会被执行一次
public String intercept(ActionInvocation invocation) throws Exception {
System.out.println("------MyInterceptor11 invoked begin------");
//调用invoke()方法
//如果还有下一个拦截器的话,就执行下一个拦截器
//如果没有下一个拦截器的话,便执行Action中的方法
String result = invocation.invoke();
System.out.println("------MyInterceptor11 invoked finish------");
return result;
}
}
要点:1,Struts2中的拦截器是用来拦截Action的,它相当于入口和出口一样,把Action的相关方法包裹在中间。拦截器栈相当于一串拦截器,用来共同地拦截某一个Action,拦截的顺序是按照配置的顺序执行的,但是结束却是按照配置的倒序执行的。
2,也就是说首先会进入第一个拦截器,出来后再进入第二个,依次类推,最后进入Action的execute()方法。当execute()执行后,再按照相反的顺序,先回到第二个拦截器,再回到第一个,最后才回到结果视图。因此invoke()就是用来判断,若还有下一个拦截器,就调用下一个,否则直接跳到Action的execute()方法。
三,也可以写继承了AbstractInterceptor类的自定义拦截器。
package com.jadyer.interceptor;
import java.util.Map;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
/**
* 继承AbstractInterceptor类的自定义拦截器
* @see 【这种方式比较常用】
* @see 继承AbstractInterceptor之后,就不需要再去实现init()和destroy()方法了
* @see 所以实际应用中,更多的时候还是继承AbstractInterceptor,而不是实现Interceptor
* @see ------------------------------------------------------------------------------------------------------------
* @see 也可以用下面这种方式来配置
* @see <package name="scriptHit" extends="struts-default">
* @see <interceptors>
* @see <interceptor name="ScriptHitInterceptor" class="com.jadyer.interceptor.ScriptHitInterceptor"/>
* @see <interceptor-stack name="scriptHitStack">
* @see <interceptor-ref name="ScriptHitInterceptor"/>
* @see <interceptor-ref name="defaultStack"/>
* @see </interceptor-stack>
* @see </interceptors>
* @see <default-interceptor-ref name="scriptHitStack"/>
* @see </package>
* @see ------------------------------------------------------------------------------------------------------------
*/
@SuppressWarnings("serial")
public class MyInterceptor extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation invocation) throws Exception {
System.out.println("------------ScriptHitInterceptor invoked begin------------");
//获取请求的方法名,得到的方法名不包含括号,例如methodName=preLoginCheck
System.out.println("获取请求方法:methodName=" + invocation.getInvocationContext().getName());
//获取请求的参数名和参数值
Map<string object=""> parameters = invocation.getInvocationContext().getParameters();
for(Map.Entry<string object=""> entry : parameters.entrySet()){
//借助parameters根据参数名获取参数值对象,其实得到的参数值对象是一个字符串数组,该数组第一个元素即真实参数值
System.out.println("获取请求参数:" + entry.getKey() + "=" + ((String[])parameters.get(entry.getKey()))[0]);
//修改下参数值
parameters.put(entry.getKey(), new String[]{"jadyer" + ((String[])parameters.get(entry.getKey()))[0]});
}
//填加一个参数,这里指定其值为jadyer
//Struts2之所以采用字符串数组的方式,或许是为了应对参数名或参数值相同的情况吧
parameters.put("myname", new String[]{"jadyer"});
//再次获取参数名和参数值
for(Map.Entry<string object=""> entry : parameters.entrySet()){
System.out.println("重新获取参数:" + entry.getKey() + "=" + ((String[])parameters.get(entry.getKey()))[0]);
}
//也可以通过HttpServletRequest获取真实参数值,不过它获取到的是最原始的请求参数值,而非上面我们改动过的参数值
//如果在Struts2的Action中通过ServletActionContext.getRequest().getParameter("fromBanner")获取参数值的话
//那么后台获取到的也只是原始的请求参数值fromBanner=yes,而非fromBanner=jadyeryes
for(Map.Entry<string object=""> entry : parameters.entrySet()){
System.out.println("再次获取参数:" + entry.getKey() + "=" + ServletActionContext.getRequest().getParameter(entry.getKey()));
}
String result = invocation.invoke();
System.out.println("------------ScriptHitInterceptor invoked finish------------");
return result;
}
}
四,还可以写继承了MethodFilterInterceptor拦截器类的自定义拦截器MyInterceptor33.java。
package com.jadyer.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
/**
* 继承MethodFilterInterceptor的拦截器,即方法过滤的拦截器
* @see 查看MethodFilterInterceptor的源码可知,它也是一个拦截器类,它继承了AbstractInterceptor
* @see 观察它的类名,可以发现,它就是一个拦截某一个具体的方法的方法过滤拦截器
* @see 而MethodFilterInterceptor类已经自动实现好了Intercept()方法
* @see 实际上MethodFilterInterceptor类中的Intercept()方法真正执行的是它本身的一个doIntercept()抽象方法
* @see 因此,我们想要拦截某一个方法的时候,只要继承MethodFilterInterceptor类,然后实现doIntercept()便OK
*/
@SuppressWarnings("serial")
public class MyInterceptor33 extends MethodFilterInterceptor {
@Override
protected String doIntercept(ActionInvocation invocation) throws Exception {
System.out.println("------MyInterceptor33 invoked begin------");
String result = invocation.invoke();
System.out.println("------MyInterceptor33 invoked finish------");
return result;
}
}
要点:工作时经常碰到的是这种拦截器。