前一个例子讲了对于前台数据的拦截。但是问题出现了,我们定义了拦截器后,它会对Action下面的所有方法进行拦截。有时候,我们只需要拦截Action中的部分方法,怎么办呢?
1.方法的过滤
我们就要通过过滤的方式。
struts2提供了一个MethodFilterInterceptor类,该类是AbstractInterceptor类的子类,如果用户需要自己实现的拦截器支持方法过滤,则应该继承MethodFilterInterceptor类。该类需要实现一个方doInterceptor(ActionInvocation invocation)
实现过滤的方法和普通拦截器并没有太大区别,只需要继承MethodFilterInterceptor类和实现该类的doInterceptor方法便可。
但是注意的一点是:
MethodFilterInterceptor类中,增加了两个方法
1)public void setExcludeMethods(String excludeMethods):
作用:排除需要过滤的方法
2)public void setIncludeMethods(String includeMethods):
设置需要过滤的方法
看struts.xml配置文件中怎么写
<interceptors>
<interceptor name="a1" class=""></interceptor>
</interceptors>
<action name="los" class="">
<interceptor-ref name="拦截器名">
<param name="excldeMethods">execute</param>
</interceptor-ref>
</action>
可以看到,execludeMethods标签去掉了execute()方法,也就是拦截器不会拦截execute方法,如果要设置多个方法不被拦截,可以通过下面的代码
<package name="t" extends="struts-default">
<interceptors>
<interceptor name="a1" class=""></interceptor>
</interceptors>
<action name="los" class="">
<interceptor-ref name="拦截器名">
<param name="excldeMethods">execute,add,delete</param>
</interceptor-ref>
</action>
</package>
如果includeMethods同时选中一个方法,那该方法默认被选中,也就是遵循includeMethods的选择。
2.拦截器监听的结果
前面例子中,我们执行完invocation.invoke()方法后,执行execute后,会继续执行没有执行完的代码,这样结构上看上不不清晰。
为了说明execute()方法结束后再执行Result执行的动作,Struts2提供了用于拦截器结构的监听器,这个监听器是通过手工注册到拦截器内部的。
实现拦截器的监听要实现PreResultListener接口,其代码如下:
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.PreResultListener;
public class TestPreResultListener implements PreResultListener {
public void beforeResult(ActionInvocation invocation,String resultCode){
System.out.println("最后逻辑视图为:"+resultCode);
}
}
与前面直接在intercepte方法中定义的,在execute()方法执行之后执行的代码相比,在beforeResult()方法内有另一个参数:resultCode,这个参数就是被拦截Action的execute()方法的返回值。
虽然上面的beforeResult()也获得了ActionInvocation类型的参数,但通过这个参数来控制Action的作用已经不再那么明显——因为Action的execute()方法已经执行完了。
监听器需要通过代码手动注册给某个拦截器,需要在拦截器类中的intercept(ActionInvocation invocation)方法中加上下面代码进行注册监听器。
invoaction.addPreResultListener(new TestPreResultListener());
通过代码手动注册了一个拦截结果的监听器TestPreResultListener,该监听器中的Result()方法肯定会在系统处理Result之前执行。
虽然beforeResult()方法中再对ActionInvocation方法处理已经没有太大意义,但是Action已经执行完毕,而Result还没有开始执行的时间点也非常重要,可以让开发者精确控制到Action处理的结果,并且对处理结果做出针对性的处理。
3.Struts2自带拦截器
如果<package> extends了struts-default包,那就可以使用默认拦截器。但是如果引用了自定的拦截器,那必须要显示的声明引用默认拦截器。
struts2的内置拦截器概览:
拦截器名 | 功能 |
---|---|
alias | 实现在不同请求中相似参数别名的转换 |
autowiring | 这个是自动装配的拦截器,主要用于当struts2和spring整合时,struts可以使用自动装配的方式访问spring容器中的bean |
chain | 构建一个Action链,使当前Action可以访问前一个Action的属性,一般和<result type="chain".../>一起使用 |
conversionError | 这是一个负责处理类型转换错误的拦截器,它负责将类型转换错误从ActionContext中取出,并转换成Action的FieldError错误 |
createSession | 该拦截器负责创建一个HttpSession对象,主要用于那些需要HttpSession对象才能正常工作的拦截器 |
debugging | 当使用struts2的开发模式时,这个拦截器将提供更多的调试信息 |
execAndWait | 后台执行Action,负责将等待画面发送给用户 |
exception | 这个拦截器负责处理异常,它将异常映射为结果 |
fileUpload | 这个拦截器主要用于文件上传,它负责解决表单文件域的内容 |
il8n | 这是支持国际化的拦截器,它负责把所选的语言、区域放入用户的session中 |
logger | 这个是负责日志记录的拦截器,主要输出Action的名字 |
model-driven | 这是一个用于模型驱动的拦截器,当某个Action类实现了ModelDriven接口时,它负责把getModel()方法的结果放入ValueStack中 |
scoped-model-driven | 如果一个Action实现了ScopedModelDriven接口,该拦截器负责从指定生成范围中找出指定的Model,并通过setModel()方法将该Model传给Action实例 |
params | 这是一个最基本的拦截器,它负责解析HTTP请求中的参数,并将参数值设置成Action对应的属性 |
prepare | 如果Action实现了Prepareable接口,将会调用该拦截器的parepare()方法 |
static-params | 该拦截器负责将xml中<action>标签下的<param>标签中的参数传入Action |
scope | 这是范围转换拦截器,它可以将Action状态信息保存到HttpSession范围,或者保存到ServletContext范围中 |
servlet-config | 如果某个Action需要直接访问Servlet API,就是通过这个拦截器实现的 |
roles | 这是一个JAAS(Java Authentication and Authorization Service,Java授权和认证服务)拦截器,只有当浏览者取得合适的授权后,才可以调用被拦截器拦截的Action |
timer | 这个拦截器负责输出Action的执行时间,这个拦截器在分析该Action的性能瓶颈时比较常用 |
token | 这个拦截器用于防止重复提交,它检查到Action中的token,从而防止多次提交 |
token-Session | 这个拦截器的作用于前一个基本类似,只是它把token保存在HttpSession中 |
validation | 通过执行在xxxAction-validation.xml中定义的校验器,从而完成数据校验 |
workflow | 这个拦截器负责调用Action类中的validate()方法,如果校验失败,则返回input的逻辑视图 |
4.使用拦截器注解
Struts2在com.opensymphony.xwork2.interceptor.annotations包中定义了3个拦截器注解类型,可以通过注解的方式指定在Action前或者Action后需要调用的方法。
1)Before
用于标注一个Action方法,该方法将在 Action的execute方法执行之前调用。如果标注的方法有返回值,且不为null,那它的返回结果将作为Action的结果代码。
2)After
用于标注一个Action方法,该方法将在Action的execute方法执行之后且result执行之后调用。有返回值 返回值也将被忽略
3)BeforeResult
标识一个Action方法,该方法将在Action的主要方法调用之后,在result方法调用之前调用。
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.interceptor.annotations.Before;
import com.zhuxuli.model.User;
public class LoginAction extends ActionSupport {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Before
public String checkUser(){
ActionContext context=ActionContext.getContext();
Map Session=context.getSession();
if(user!=null&&user.getUsername().equals("micheal")){
Session.put("user", user);
return null;
}else{
return "input";
}
}
public String execute() throws Exception{
return "main";
}
}
并且struts.xml中要配置相应的拦截器
<package name="logs" extends="struts-default">
<interceptors>
<interceptor name="annotationInterceptor" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor">
</interceptor>
<interceptor-stack name="annotatedStack">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="annotationInterceptor"></interceptor-ref>
</interceptor-stack>
</interceptors>
<global-results>
<result name="error">/error.jsp</result>
</global-results>
<action name="logs" class="com.zhuxuli.action.LoginAction">
<result name="input">/index.jsp</result>
<result name="main">/main.jsp</result>
<interceptor-ref name="annotatedStack"></interceptor-ref>
</action>
</package>
在上边,拦截器中定义了Struts2的com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor拦截器,然后再拦截器栈中定义了默认拦截器栈和本拦截器。在Action中引用。
这样的话,每当页面提交信息后,表单首先通过了Before注释的方法的验证,如果返回空,将执行execute()方法,如果不为空,那就会作为result的结果返回逻辑视图。