Struts2 Learning (5) Introduction to Interceptors

what is an interceptor

 

Interceptor ( Interceptor ) is a powerful tool of Struts 2 , many functions are built on it, such as internationalization, converters, verification and so on.

An interceptor is an object that dynamically intercepts Action calls . It provides a mechanism that allows developers to define code to be executed before and after an action is executed , and to prevent the execution of an action before it is executed . It also provides a way to extract reusable parts of an action .

When it comes to interceptors, there is one thing that can't be dropped - the interceptor chain ( Interceptor Chain , called the Interceptor Stack in Struts 2 ).

The interceptor chain is to link the interceptors into a chain in a certain order. When an intercepted method or field is accessed, the interceptors in the interceptor chain are called in the order in which they were previously defined.

 

Implementation principle

 

Struts 2 's interceptor implementation is relatively simple. When the request arrives at the ServletDispatcher of Struts 2 , Struts 2 will look up the configuration file and instantiate the relative interceptor object according to its configuration, then string it into a list ( list ), and finally call the interceptors in the list one by one.


Interceptor call sequence diagram

demo

 

Let's first create a simple interceptor to demonstrate

 

First create the first interceptor FirstInterceptor

package cn.lovepi.chapter05.interceptor;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

/**
 * Created by icarus on 2016/7/9.
 * Interceptor demo
 */
public class FirstInterceptor implements Interceptor {
   private String some;
    /**
     * Interceptor destroy method
     */
    @Override
    public void destroy() {

    }

    /**
     * Initialization method, the interceptor has been initialized when the system starts
     */
    @Override
    public void init() {
        System.out.println(some+"Interceptor initialization completed");
    }

    /**
     * Interceptor core code
     * @param actionInvocation
     * @return
     * @throws Exception
     */
    @Override
    public String intercept(ActionInvocation actionInvocation) throws Exception {
        // Let the request that arrives at the interceptor move on and access the resource that needs to be accessed,
        // That is to say, put it in the past, the return value is the return string after the action
        // This string goes to result in struts.xml.
        System.out.println("Enter the First interceptor");
        String returnName=actionInvocation.invoke();
        System.out.println("Exit First interceptor");
        System.out.println("returnName"+returnName);
        return returnName;
    }

    public String getSome() {
        return some;
    }

    public void setSome(String some) {
        this.some = some;
    }
}
Configure the interceptor in the file
<package name="chapter05" extends="struts-default">
         <!--The interceptor must be configured in the first position under the package package-->
         <interceptors>
             <interceptor name="ch05FirstInterceptor" class="cn.lovepi.chapter05.interceptor.FirstInterceptor">
                 <!--Configuration property value-->
                 <param name="some">icarus</param>
             </interceptor>
         </interceptors>
         <!--Interceptor Demonstration Action-->
         <action name="ch05LoginAction" class="cn.lovepi.chapter05.action.LoginAction">
             <interceptor-ref name="ch05FirstInterceptor"/>
             <!--The default interceptor must be configured-->
             <interceptor-ref name="defaultStack"/>
             <result name="success">/chapter05/login.jsp</result>
         </action>
</package>

You can see that our interceptor must be configured in the first position under the package package, using the <interceptors> tag to configure, you can configure multiple interceptors, and use the <interceptor> tag to configure. You can also set its properties in the interceptor, and use the <param> tag to assign values ​​to its properties.

After configuring the interceptor, if you want to use the interceptor in an Action , use the <interceptor-ref> tag to specify it.

 

Note : In fact, the system will execute the default interceptor before executing the Action , which means that each Action tag actually has a sentence:

<interceptor-ref name="defaultStack"/>
But this situation changes after you configure a custom interceptor. The custom interceptor will overwrite the default interceptor . At this time, only one custom interceptor works in the system, but we know that many functions in Struts2 are implemented based on the default interceptor, such as internationalization, conversion device, checksum, etc. So we must introduce the default interceptor to the Action after introducing the custom interceptor .


Next we create the second interceptor SecondInterceptor

package cn.lovepi.chapter05.interceptor;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

/**
 * Created by icarus on 2016/7/9.
 * Interceptor demo
 */
public class SecondInterceptor implements Interceptor {
    /**
     * Interceptor destroy method
     */
    @Override
    public void destroy() {

    }

    /**
     * Initialization method, the interceptor has been initialized when the system starts
     */
    @Override
    public void init() {
        System.out.println("Second interceptor initialization completed");
    }

    /**
     * Interceptor core code
     * @param actionInvocation
     * @return
     * @throws Exception
     */
    @Override
    public String intercept(ActionInvocation actionInvocation) throws Exception {
        // Let the request that arrives at the interceptor move on and access the resource that needs to be accessed,
        // That is to say, put it in the past, the return value is the return string after the action
        // This string goes to result in struts.xml.
        System.out.println("Enter Second interceptor");
        String returnName=actionInvocation.invoke();
        System.out.println("Exit Second Interceptor");
        return returnName;
    }
}
Next, configure the second interceptor in the project

<package name="chapter05" extends="struts-default">
         <!--The interceptor must be configured in the first position under the package package-->
         <interceptors>
             <interceptor name="ch05FirstInterceptor" class="cn.lovepi.chapter05.interceptor.FirstInterceptor">
                 <!--Configuration property value-->
                 <param name="some">icarus</param>
             </interceptor>
             <!--Configure the second interceptor, you need to use param without related attributes-->
             <interceptor name="ch05SecondInterceptor" class="cn.lovepi.chapter05.interceptor.SecondInterceptor"/>
         </interceptors>
         <!--Interceptor Demonstration Action-->
         <action name="ch05LoginAction" class="cn.lovepi.chapter05.action.LoginAction">
             <interceptor-ref name="ch05FirstInterceptor"/>
             <interceptor-ref name="ch05SecondInterceptor"/>
             <!--The default interceptor must be configured-->
             <interceptor-ref name="defaultStack"/>
             <result name="success">/chapter05/login.jsp</result>
         </action>
</package>


Execute the project and you will find that the output is:





This leads to a very important concept in the interceptor - the interceptor stack

The execution order of the interceptor stack can be abstracted into the following patterns:



The corresponding interceptor stack can also be represented by the <interceptor-stack> tag in the Struts.xml file

Then the configuration file of the above example can be changed into the following form:

<package name="chapter05" extends="struts-default">
         <!--拦截器必须得配置在package包下第一个位置-->
         <interceptors>
             <interceptor name="ch05FirstInterceptor" class="cn.lovepi.chapter05.interceptor.FirstInterceptor">
                 <!--配置属性值-->
                 <param name="some">icarus</param>
             </interceptor>
             <!--配置第二个拦截器,没有相关属性就需要使用param了-->
             <interceptor name="ch05SecondInterceptor" class="cn.lovepi.chapter05.interceptor.SecondInterceptor"/>
             <!--拦截器栈配置-->
             <interceptor-stack name="cho5AllInterceptor" >
                 <interceptor-ref name="ch05FirstInterceptor"/>
                 <interceptor-ref name="ch05SecondInterceptor"/>
                 <!--必须设置默认拦截器-->
                 <interceptor-ref name="defaultStack"/>
             </interceptor-stack>
         </interceptors>
         <!--拦截器演示Action-->
         <action name="ch05LoginAction" class="cn.lovepi.chapter05.action.LoginAction">
             <!--只需引入一个拦截器即可-->
             <interceptor-ref name="cho5AllInterceptor"/>
             <result name="success">/chapter05/login.jsp</result>
         </action>
</package>

在这里便可以引入一个新的概念,全局拦截器全局result

<!--系统默认拦截器,对这个包中的所有action都适用-->
<default-interceptor-ref name="cho5AllInterceptor"/>
<!--全局的返回result,当包中任何一个action方法返回error都会去error界面-->
<global-results>
     <result name="error">/error.jsp</result>
</global-results>

还有一些其他的全局设置参数,因为不长使用便不在介绍了,可以自行了解。

 

我们目前所设置的Action都是直接使用一个类来实现ActionSupport接口,并重写接口默认的execute方法来实现的。所有的逻辑代码全在一个方法中,这对于一个类来说其实是有些浪费的,假如我们需要实现一个功能当中的增删改查方法的话岂不是要编写四个类…….

其实我们是可以在Action类中设置自己的方法的,只需在配置文件中配置到对应的方法即可。

 

如下我们在一个继承了ActionSupport类中编写了adddeleteupdateshow四个方法

package cn.lovepi.chapter05.action;

import com.opensymphony.xwork2.ActionSupport;

/**
 * Created by icarus on 2016/7/9.
 * 通配符引入示例
 */
public class UsersAction extends ActionSupport{
//    /**
//     * 默认的execute方法
//     * @return
//     * @throws Exception
//     */
//    @Override
//    public String execute() throws Exception {
//        System.out.println("进入execute方法");
//        return SUCCESS;
//    }
    /*
    但是对于一个类来说,只有一个执行方法是有些浪费的。
    我们可以自定义一些方法,然后在struts.xml文件中配置相应的方法
     */
    public String add() throws Exception{
        System.out.println("进入add方法");
        return "add_success";
    }
    public String show() throws Exception{
        System.out.println("进入show方法");
        return "show_success";
    }
    public String update() throws Exception{
        System.out.println("进入update方法");
        return "update_success";
    }
    public String delete() throws Exception{
        System.out.println("进入delete方法");
        return "delete_success";
    }
}
我们可以在类中对每个方法的 Action 进行配置
 <action name="chapter05UsersActionAdd" class="cn.lovepi.chapter05.action.UsersAction" method="add">
     <result name="success">/chapter05/index.jsp</result>
</action>
<action name="chapter05UsersActionShow" class="cn.lovepi.chapter05.action.UsersAction" method="show">
     <result name="success">/chapter05/index.jsp</result>
</action>
<action name="chapter05UsersActionUpdate" class="cn.lovepi.chapter05.action.UsersAction" method="update">
     <result name="success">/chapter05/index.jsp</result>
</action>
<action name="chapter05UsersActionDelete" class="cn.lovepi.chapter05.action.UsersAction" method="delete">
     <result name="success">/chapter05/index.jsp</result>
</action>

但是这样配置起来过于繁琐

 

接下来我们使用通配符来进行配置:

通配符可用于代替字符。通常地,星号“*”匹配0个或以上的字符,问号“?”匹配1个字符。

 

这样的话,上面的那些action可以用如下的代码进行配置:

<!--使用通配符方法配置,说白了就是在数星星,第一个星星的内容用{1}来代表-->
<action name="users_*" class="cn.lovepi.chapter05.action.UsersAction" method="{1}">
       <interceptor-ref name="ch05MethodInterceptor"/>
       <!--必须配置默认的拦截器-->
       <interceptor-ref name="defaultStack"/>
       <result name="{1}_success">/chapter05/{1}index.jsp</result>
</action>

在这里我们是对方法进行拦截器,所有我们得使用对应的方法拦截器

方法拦截器和普通的拦截器有所不同,普通的拦截器是实现Interceptor接口而方法拦截器是继承自MethodFilterInterceptor

package cn.lovepi.chapter05.interceptor;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;

/**
 * Created by icarus on 2016/7/10.
 * 方法拦截器,只针对对应的方法来进行拦截
 */
public class MethodInterceptor extends MethodFilterInterceptor{
    @Override
    protected String doIntercept(ActionInvocation actionInvocation) throws Exception {
        System.out.println("进入方法拦截器");
        String returnName=actionInvocation.invoke();
        System.out.println("退出方法拦截器");
        return returnName;
    }
}

这实际开发中,正确使用通配符来编写配置文件可以大大提高我们的开发效率同时也可以规范我们的代码。

<!--实际项目开发中所使用的通配符配置,第一个*是类名,第二个*是类中对应的方法
在表单的action中也要按照这种方式来编写
其实,使用通配符来配置同时也是一种编码规范-->
<action name="*_*" class="cn.lovepi.chapter05.action.{1}Action" method="{2}">
   <result name="{1}_{2}_success">/chapter05/{1}{2}index.jsp</result>
</action>






Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325716783&siteId=291194637