且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Struts2拦截器的简单应用,登录权限拦截器及与过滤器的区别(八)上

更新时间:2022-05-28 05:03:07

Struts2的拦截器,功能非常强大,很多强有力的功能都是通过拦截器实现的。我们输入一个网址,为什么只配置了过滤器和struts.xml文件中的action,就会去执行Action呢? 就是因为拦截器的存在。


Struts2框架已经默认为我们的每一个自定义的action都实现了一个拦截器default-stack。 其中拦截器的相关配置在struts-core核心包下的struts-default.xml文件中。


Struts2拦截器的简单应用,登录权限拦截器及与过滤器的区别(八)上


拦截器是在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

查看控制台日志打印:


Struts2拦截器的简单应用,登录权限拦截器及与过滤器的区别(八)上


可以发现拦截器配置完成.


提示: (在操作时,不要忘记配置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>