1、Struts2中使用拦截器来扩展Action的功能,往往是用来处理Action之间通用的事务,比如:记录日志、权限检查、控制事务。并且这种方式是可配置的,灵活很高,这种方式大大的提升了Struts2框架的扩展性。是AOP思想的一种体现。
2、Struts2中预置了大量的拦截器,我们可以直接使用,这些拦截器定义在struts-default.xml中,每一个拦截器都对应一个类,这些类都实现了统一的接口Interceptor。
3、拦截器的使用步骤
a.创建拦截器组件(类),要实现Interceptor接口
b.在struts.xml中,package下注册该拦截器,实际上是对拦截器类的注册
c.在struts.xml中,action的配置下,增加对拦截器的引用,实际上是引用注册好的拦截器
如下面代码所示,默认struts.xml中我们需要extends="struts-default"。因为struts-default是定义在struts2-core.jar中的struts-default.xml中的一个package的name,该package中定义了struts2中所需要的各种Result type 和 interceptor,而默认已经引用的是拦截器栈 defaultStack <default-interceptor-ref name="defaultStack"/>。defaultStack会拦截所有的action不仅仅是乱码输入,最重要一个是获得页面传参,所有extends="struts-default" 是非常必要的。
<package name="valueStack" extends="struts-default" namespace="/"> <action name="hello" class="com.tarena.action.HelloAction"> <result name="SUCCESS">/demo.jsp</result> </action> </package>
但是struts2提供的拦截器并不满足我们所有的需求,我们需要自定义拦截器或者拦截器栈。
案例如下:
1) 新建类FirstInterceptor.java,implements Interceptor接口。要重写init(),destory(),intercept()方法。或者extends AbstractInterceptor,这个不太常用。
public class FirstInterceptor implements Interceptor { /* * 该方法与init()方法对应,在拦截器销毁之前,系统将回调该拦截器的destroy方法,该方法用于释放init方法中打开的资源。 */ public void destroy() { } /* * 在该拦截器被初始化之后,在该拦截器执行拦截之前,系统将回调该方法,init()方法主要是用于打开一些资源,例如数据库资源。该方法只执行一次。 */ public void init() { } /* * 拦截器的拦截方法,用于拦截Action */ public String intercept(ActionInvocation ai) throws Exception { // 模拟在Action业务方法前,追加业务 System.out.println("FirstInterceptor拦截前..."); /* * invoke()用于调用引用该拦截器的业务方法, 如果当前拦截方法中没有调用invoke(), * 那么就不会调用到Action的业务方法,从而 实现了对Action的拦截. */ ai.invoke(); // 模拟在Action业务方法后,追加业务 System.out.println("FirstInterceptor拦截后..."); /* * 如果拦截方法中调用了invoke(),那么返回值 将以被调用的Action返回值为准, 如果没调用,拦截方法中的返回值才生效 */ return "error"; } }
类SecondInterceptor.java
public class SecondInterceptor implements Interceptor { public void destroy() { } public void init() { } public String intercept(ActionInvocation ai) throws Exception { System.out.println("SecondInterceptor拦截前..."); ai.invoke(); System.out.println("SecondInterceptor拦截后..."); return "error"; } }
2) 在struts.xml 的 package下注册拦截器
<!-- 注册拦截器 --> <interceptors> <interceptor name="first" class="com.lydia.interceptor.FirstInterceptor" /> <interceptor name="second" class="com.lydia.interceptor.SecondInterceptor" /> <interceptor-stack name="mystacks"> <interceptor-ref name="first"/> <interceptor-ref name="second"/> </interceptor-stack> </interceptors>
3)在struts.xml中,action的配置下,引用对拦截器
<!-- 引用拦截器 --> <interceptor-ref name="first"/> <interceptor-ref name="second"/> <!-- 引用拦截器栈 (二选一即可)--> <!--<interceptor-ref name="mystacks"/>--> <interceptor-ref name="defaultStack"/>
4) HelloAction.java按照原定业务操作,它会默认调用拦截器的。
public class ToUpdateCustomerAction { //input,由于是模拟的代码,不给输入了 //output private Customer customer; private List<City> cities; public ToUpdateCustomerAction() { System.out.println("实例化Action..."); } public String execute() { System.out.println("Action业务方法..."); CustomerDAO dao = new CustomerDAO(); customer = dao.findById(); cities = dao.findAllCities(); return "success"; } //get/set方法省略 }
5) 执行顺序和结果
实例化Action...
FirstInterceptor拦截前...
SecondInterceptor拦截前...
Action业务方法...
SecondInterceptor拦截后...
FirstInterceptor拦截后...