1、自定义拦截器
在Struts自带的配置文件struts-default.xml中,定义了默认包struts-default,这个包中定义了很多的拦截器,这些拦截器的作用是在请求访问到action之前和访问action之后进行拦截操作。一般自己在struts.xml中,如果不去指定拦截器,那么就会执行一组默认的拦截器:<default-interceptor-ref name="defaultStack"/>
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="datetime"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="debugging"/>
<interceptor-ref name="deprecation"/>
</interceptor-stack>
这些拦截器会对数据进行一系列的预处理,我们也可以在struts.xml中定义自己的拦截器和拦截器组,但是需要注意的是,即使定义了自己的拦截器组,也要执行默认的拦截器组,否则会发现很多问题,比如即使action实现了ModelDrivern接口,也无法获取到对象的值,这是因为这些封装就在默认的拦截器中,拦截器之间是从上到下递归调用的。
参考这些配置文件,web.xml,struts-default.xml,struts.xml以及源码,我们可以得出Struts2框架调用的基础完整流程,大致描述如下:
浏览器发起请求→web.xml中定义的struts2的核心过滤器会拦截请求,进入Struts2的数据处理流程→在该核心过滤器中的dofilter方法里,会判断当前的请求是否为访问action的请求,如果不是,直接放行,与Struts2后续处理流程无关,如直接访问html页面。而如果是访问action,此时会创建这个action的代理对象,invocation.invoke()调用invoke方法,获取所有配置的拦截器,依次递归调用→当拦截器执行完成后,会执行对应的action的方法→当action执行完成之后,会逆向再调用一次指定的过滤器(存疑?),最终返回一个逻辑视图名,根据配置文件到达最终的结果页面。
此处需要区分一下拦截器与过滤器的区别:
过滤器属于web端的技术 /* 拦截所有资源 html 图片 jsp servlet...全部都拦
拦截器属于struts2的技术 /* 只拦截action html 图片 jsp 全部放行,不拦截
那么我们如何定义自己的拦截器来处理自己想要做的数据处理?可以直接模仿struts-default.xml来进行配置,描述如下:
a、创建一个拦截器,这个拦截器一般以Interceptor结尾,且必须实现Interceptor接口或者继承AbstractInterceptor类或者继承MethodFilterInterceptor类
b、在struts.xml中声明这个拦截器
c、声明拦截器组,也可以不声明拦截器组直接在action中配置调用单个拦截器。但是需要注意的是自己声明的拦截器组最好包含默认拦截器组,一个拦截器组中可以有一个或多个拦截器,拦截器组之间可以互相调用,一个拦截器可以出现在多个拦截器组中
d、在action标签内部声明需要执行的拦截器
*此外,拦截器可以执行拦截的方法,如果要进行指定,那么该拦截器必须继承MethodFilterInterceptor类,然后在拦截器标签内部通过param标签来指定需要拦截的函数和不需要拦截的函数,param的name值为excludeMethods时,代表不拦截该方法,多个方法用逗号隔开,为includeMethods时,代表拦截该方法。
以下为一个声明了拦截器的struts.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<package name="test1" extends="struts-default" namespace="/">
<!--全局的: 为page下面的所有action申明拦截器 -->
<interceptors>
<interceptor name="MyInterceptor1" class="cn.itcast.interceptor.MyInterceptor1"></interceptor>
<interceptor name="MyInterceptor2" class="cn.itcast.interceptor.MyInterceptor2"></interceptor>
<interceptor name="MyInterceptor3" class="cn.itcast.interceptor.MyInterceptor3">
<!-- 指定不拦截的方法 -->
<param name="excludeMethods">findAll</param>
</interceptor>
<interceptor-stack name="MyInterceptors">
<!--调用默认组的 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="MyInterceptor2"></interceptor-ref>
<interceptor-ref name="MyInterceptor1"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 执行在访问action的时候 需要执行的拦截器组 -->
<default-interceptor-ref name="MyInterceptors"></default-interceptor-ref>
<action name="ad1" class="cn.itcast.action.ActionDemo1" >
<!-- 局部的 可以指定拦截器组 也可以指定单个拦截器 -->
<interceptor-ref name="MyInterceptor1"></interceptor-ref>
<interceptor-ref name="MyInterceptor2"></interceptor-ref>
<result name="ok">/1.jsp</result>
</action>
<action name="ad2" class="cn.itcast.action.ActionDemo2" >
<!-- 单个拦截器 -->
<interceptor-ref name="MyInterceptor2"></interceptor-ref>
<!-- 拦截器组 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
<result name="ok">/1.jsp</result>
</action>
<action name="ad3" class="cn.itcast.action.ActionDemo3" method="findAll">
<interceptor-ref name="MyInterceptor3"></interceptor-ref>
<result name="ok">/1.jsp</result>
</action>
</package>
</struts>
2、Struts2的注解
可以使用注解代替package标签的配置,首先需要导入struts2的注解包struts2-convention-plugin-2.3.24.jar,然后必须注意的是,需要注解的action必须在action actions struts struts2含有这些名称包名下,这是因为struts2只会去他们这些包名下加载注解,四个最主要的注解举例如下:
把action从配置文件的方式变成注解的方式
<package name="test1" extends="struts-default" namespace="/">
<action name="ad4" class="cn.itcast.action.ActionDemo4" >
<interceptor-ref name="defaultStack"></interceptor-ref>
<result name="ok">/1.jsp</result>
</action>
</package>
@ParentPackage("struts-default") 定义在action类上的 指定继承的父包
@Namespace("/") 定义在action类上的 命名空间
@Action(value="ad4") 定义在方法上的 指定该方法的访问路径
@Action(@Result(name="oko",location="/2.jsp")}) 定义在方法上 指定返回的逻辑视图名 根据逻辑视图到指定的页面
这2个注解可以合并写在一起
package cn.itcast.action;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import cn.itcast.domain.User;
// 注解
@ParentPackage("struts-default")
@Namespace("/")
public class ActionDemo4 extends ActionSupport
{
@Action(value="ad4",results={@Result(name="ok",location="/1.jsp"),@Result(name="oko",location="/2.jsp")})
public String execute() throws Exception {
return "ok";
}
}