Struts2的拦截器,功能非常强大,很多强有力的功能都是通过拦截器实现的。我们输入一个网址,为什么只配置了过滤器和struts.xml文件中的action,就会去执行Action呢? 就是因为拦截器的存在。
Struts2框架已经默认为我们的每一个自定义的action都实现了一个拦截器default-stack。 其中拦截器的相关配置在struts-core核心包下的struts-default.xml文件中。
拦截器是在Action执行方法前被调用,在方法执行后被销毁。
一. Struts2提供的关于拦截器的接口和类
一.一 Struts2官方提供的拦截器Interceptor接口
package com.opensymphony.xwork2.interceptor; import com.opensymphony.xwork2.ActionInvocation; import java.io.Serializable; public abstract interface Interceptor extends Serializable { public abstract void destroy(); public abstract void init(); public abstract String intercept(ActionInvocation paramActionInvocation) throws Exception; }
destroy()方法是销毁,init()是初始化, intercept() 方法才是我们真正要关注的方法。
我们编写拦截器,一般不使用实现这个接口,而是继承它的实现类AbstractInterceptor
一.二 抽象类AbstractInterceptor
package com.opensymphony.xwork2.interceptor; import com.opensymphony.xwork2.ActionInvocation; public abstract class AbstractInterceptor implements Interceptor { public void init() {} public void destroy() {} public abstract String intercept(ActionInvocation paramActionInvocation) throws Exception; }
这个抽象类AbstractInterceptor实现了Interceptor接口,并且重写了init()方法和destroy()方法,用户只需要实现interceptor()方法即可。
我们用这个抽象类做一个简单的拦截器,实际开发中也并不用这一个抽象类AbstractInterceptor。
二. 简单自定义一个拦截器
二.一 新建拦截器类MyInterceptor ,继承AbstractInterceptor类
前堤已经有了一个基本的Struts2的运行环境,延用上一章的struts2的配置和Action
在com.yjl.web.interceptor包下新建一个MyInterceptor类,让其继承AbstractInterceptor类
package com.yjl.web.interceptor; import org.apache.log4j.Logger; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; /** * @author 两个蝴蝶飞 * @version 创建时间:Aug 25, 2018 4:03:21 PM * 类说明 */ public class MyInterceptor extends AbstractInterceptor{ private static final long serialVersionUID = -6424208964705287809L; private Logger logger=Logger.getLogger(MyInterceptor.class); @Override public String intercept(ActionInvocation actionInvocation) throws Exception { logger.info("******开始执行拦截器*******"); String result=actionInvocation.invoke(); logger.info("执行后的结果为:"+result); logger.info("********结束执行拦截器**********"); return result; } }
二.二 创建Action控制器,MyInterceptorAction
在MyInterceptorAction中,返回SUCCESS字符串
public class MyInterceptorAction extends ActionSupport{ private static final long serialVersionUID = 8278845997106407817L; public String getForm(){ return SUCCESS; } }
二.三 在struts.xml中package标签下实例化拦截器
自定义的拦截器,刚开始定义好后,并不知道属于哪一个action,所以实例化拦截器放在 包下,用一个标签包起来,里面放置标签,这个标签有name和class两个属性,通过反射可以自己实例化自定义的拦截器。
<package name="interceptor" extends="struts-default" namespace="/"> <interceptors> <!-- 定义单个拦截器 --> <interceptor name="myInterceptor" class="com.yjl.web.interceptor.MyInterceptor"> </interceptor> </interceptors> <!-- 配置跳转页面 --> <action name="*"> <result>/WEB-INF/content/{1}.jsp</result> </action> </package>
二. 四 在struts.xml中action标签下引用具体的拦截器
<package name="interceptor" extends="struts-default" namespace="/"> <interceptors> <!-- 定义单个拦截器 --> <interceptor name="myInterceptor" class="com.yjl.web.interceptor.MyInterceptor"> </interceptor> </interceptors> <action name="Interceptor_*" class="com.yjl.web.action.MyInterceptorAction" method="{1}"> <!-- 引入自定义拦截器 --> <interceptor-ref name="myInterceptor"></interceptor-ref> <!-- 配置跳转页面 --> <result name="success">/WEB-INF/content/form.jsp</result> </action> <!-- 配置跳转页面 --> <action name="*"> <result>/WEB-INF/content/{1}.jsp</result> </action> </package>
二.五 编写 /content/form.jsp 页面
<body> 拦截器跳转后页面 </body>
二.六 测试验证拦截器
重启服务器,输入网址:http://localhost:8080/Struts_Interceptor/Interceptor_getForm
查看控制台日志打印:
可以发现拦截器配置完成.
提示: (在操作时,不要忘记配置web.xml中struts的过滤器)
三. 拦截器配置过程中的扩展
上面例子只是一个简单的拦截器,在实际项目中可能会配置多个拦截器,每个拦截器有不同的功能。复杂的拦截器该如何配置呢?
三.一 默认拦截器 defaultStack
可以查看struts-core.jar包下的struts-default.xml中的配置,注意查看示例. 这里简单一下里面的配置
<!--注意名称: 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="multiselect"/> <interceptor-ref name="staticParams"/> <interceptor-ref name="actionMappingParams"/> <interceptor-ref name="params"> <param name="excludeParams">^action:.*,^method:.*</param> </interceptor-ref> <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> <!--留意这一个--> <default-interceptor-ref name="defaultStack"/> <!--每一个继承ActionSupport类的Action都具有基本拦截器的功能--> <default-class-ref class="com.opensymphony.xwork2.ActionSupport" />
三.二 自定义配置多个拦截器
<interceptors> <!-- 定义单个拦截器 --> <interceptor name="myInterceptor1" class="com.yjl.web.interceptor.MyInterceptor1"> </interceptor> <interceptor name="myInterceptor2" class="com.yjl.web.interceptor.MyInterceptor2"> </interceptor> <interceptor name="myInterceptor3" class="com.yjl.web.interceptor.MyInterceptor3"> </interceptor> </interceptors>
那么在Action中引用中,用到了哪一个拦截器,就用哪一个拦截器.
假如 MyInterceptorAction中用了第二个和第三个。
<action name="Form_*" class="com.yjl.web.action.MyInterceptorAction" method="{1}"> <!-- 引入自定义拦截器 --> <interceptor-ref name="myInterceptor2"></interceptor-ref> <interceptor-ref name="myInterceptor3"></interceptor-ref> <result name="success">/WEB-INF/content/form.jsp/result> </action>
用到哪一个就配置哪一个。
三.三 拦截器栈 <interceptor-stack> </interceptor-stack>
我们的package包下开发中有多个Action(当然前堤也是interceptor拦截器多的情况下如1~30),
现在情况是 Form1Action引入了111拦截器,Form2Action引入了212拦截器,
Form3Action引入了3~13拦截器,
要是按照上面的样式配置的话,4~11会被配置成3遍,很显然不太好。
这个时候,可以将4~11配置成一个拦截器栈, 这样在引用了就比较容易引用了。
拦截器栈放在package标签下,用的是 <interceptor-stack > </interceptor-stack>
<interceptors> <!-- 定义单个拦截器 --> <interceptor name="myInterceptor1" class="com.yjl.web.interceptor.MyInterceptor1"> </interceptor> <interceptor name="myInterceptor2" class="com.yjl.web.interceptor.MyInterceptor2"> </interceptor> <interceptor name="myInterceptor3" class="com.yjl.web.interceptor.MyInterceptor3"> </interceptor> <!-- 配置拦截器栈,里面有三个拦截器 --> <interceptor-stack name="myInterceptor"> <interceptor-ref name="myInterceptor1"></interceptor-ref> <interceptor-ref name="myInterceptor2"></interceptor-ref> <interceptor-ref name="myInterceptor3"></interceptor-ref> </interceptor-stack> </interceptors>
可以根据不同的action,配置不同的interceptor-stack, 可以配置多个。
这样在配置MyInterceptorAction时,只需要简单一句
<action name="Interceptor_*" class="com.yjl.web.action.MyInterceptorAction" method="{1}"> <!-- 引入自定义拦截器栈 --> <interceptor-ref name="myInterceptor"></interceptor-ref> <result name="success">/WEB-INF/content/form.jsp</result> </action>
便具有1,2,3三个拦截器的功能了。
配置FormAction 时,也同样引用:
<action name="Form_*" class="com.yjl.web.action.FormAction" method="{1}"> <!-- 引入自定义拦截器栈 --> <interceptor-ref name="myInterceptor"></interceptor-ref> <result name="success">/WEB-INF/content/form2.jsp</result> </action>
也就具有了1,2,3三个拦截器的功能了。
三.四 默认拦截器栈 default-stack
如同Java中默认构造函数一样,Struts2提供了一个默认的拦截器栈default-stack,
如果用户自己引用了一个拦截器,无论是框架提供的,还是自定义的,
原有的拦截器栈将不在起作用了,将失效了。
默认的拦截器 default-stack中有很多的功能,如异常,别名,国际化,参数,文件上传等。 所以这些功能很重要,所以,默认的拦截器不能丢掉。
我们在引入自定义拦截器后,还需要引入默认的拦截器
<action name="Interceptor_*" class="com.yjl.web.action.MyInterceptorAction" method="{1}"> <!-- 引入自定义拦截器 --> <interceptor-ref name="myInterceptor"></interceptor-ref> <!-- 放置原有的默认的拦截器 --> <interceptor-ref name="defaultStack"></interceptor-ref> <result name="success">/WEB-INF/content/form.jsp</result> </action>
这样, MyInterceptorAction 将具有原先拦截器的功能,也具有自定义拦截器的功能。
三.五 将新的拦截器配置成默认的拦截器
可以利用 将原有的默认的defaultStack给其改变。
<interceptors> <!-- 定义单个拦截器 --> <interceptor name="myInterceptor1" class="com.yjl.web.interceptor.MyInterceptor1"> </interceptor> <interceptor name="myInterceptor2" class="com.yjl.web.interceptor.MyInterceptor2"> </interceptor> <interceptor name="myInterceptor3" class="com.yjl.web.interceptor.MyInterceptor3"> </interceptor> <!-- 注意看拦截器的配置 --> <interceptor-stack name="myInterceptor"> <interceptor-ref name="myInterceptor1"></interceptor-ref> <interceptor-ref name="myInterceptor2"></interceptor-ref> <interceptor-ref name="myInterceptor3"></interceptor-ref> <interceptor-ref name="defaultStack"></interceptor-ref> </interceptor-stack> </interceptors> <!-- 写在Action外面 --> <default-interceptor-ref name="myInterceptor"></default-interceptor-ref>
这样,就改变了默认的拦截器的值。
在Action中就不用在配置拦截器了
<action name="Interceptor_*" class="com.yjl.web.action.MyInterceptorAction" method="{1}"> <result name="success">/WEB-INF/content/form.jsp</result> </action>
注意,这个新定义的默认拦截器的作用范围是 package.
Struts2以 package 包 作为划分区域。
三.六 拦截器配置参数
用<param> </param> 进行引用。
<interceptor name="myInterceptor" class="com.yjl.web.interceptor.MyInterceptor"> <!--添加参数--> <param name="charset">UTF-8</param> </interceptor>
在MyInterceptor拦截器中,添加这个charset属性,实现setter和getter方法即可。
public class MyInterceptor extends AbstractInterceptor{ private static final long serialVersionUID = -6424208964705287809L; private Logger logger=Logger.getLogger(MyInterceptor.class); private String charset; public String getCharset() { return charset; } public void setCharset(String charset) { this.charset = charset; } //后面还有很多代码,没有复制
这样,在 struts.xml 中定义传入参数值,在过滤器中就可以引用这个参数了。
这个参数可以在拦截器定义时注入,也可以在拦截器被Action引入时注入。
**拦截器定义时引入: **
<interceptor-ref name="myInterceptor"> <param name="charset">UTF-8</param> </interceptor-ref>
拦截器被Action 引入时注入:
<interceptor name="myInterceptor" class="com.yjl.web.interceptor.MyInterceptor"> <!--添加参数--> <param name="charset">UTF-8</param> </interceptor>
三.七 公共功能拦截器配置
在项目中,常常有登录拦截器,权限验证拦截器,日志拦截器等,对于这些公共的拦截器配置,
推荐将新的拦截器栈名变成 defaultStack, 与原先的保持一致。
<interceptors> <interceptor name="loginInterceptor" class="com.yjl.web.interceptor.LoginInterceptor"> </interceptor> <interceptor-stack name="defaultStack"> <interceptor-ref name="loginInterceptor"> <interceptor-ref name="logInterceptor"> <interceptor-ref name="defaultStack"></interceptor-ref> </interceptor-stack> </interceptors>