zoukankan      html  css  js  c++  java
  • struts2(五)之struts2拦截器与自定义拦截器

    前言

      前面介绍了struts2的输入验证,如果让我自己选的话,肯定是选择xml配置校验的方法,因为,能使用struts2中的一些校验规则,就无需自己编写了,

      不过到后面应该都有其他更方便的校验方法,而不会使用struts2内置的这些校验。

      参考博文:http://www.cnblogs.com/whgk/p/6593916.html

           http://www.cnblogs.com/cxyzyh2017/p/6622827.html        

    一、struts2拦截器概述

      1)什么是拦截器?

      Struts2中的很多功能都是由拦截器完成的。比如:servletConfig,staticParam,params,modelDriven等等。

      现在应该都知道了,前面说表单提交参数自动封装时就提到了好几种拦截器,而上面说校验数据也提到了两种拦截器,基本上我们也知道拦截器的作用是啥了,

      就是在到达action之前做的很多处理,提前帮我们做事情的一种机制,而我们并不需要编写这些拦截器,因为struts2已经帮我们写好了常用的一些拦截器并且

      有个defaultStack的拦截器栈,我们使用的action就经过struts2提供的这个默认拦截器栈。其中有18个,也就是说,如果不修改默认拦截器栈,那么每次我们访

      问action,都会经过这18个拦截器栈,我们来看看哪18个。

      2)struts2的默认拦截器栈(18个拦截器)

        

      找到defaultStack

        

      其中我们应该了解很多个了,277行,i18n用来做国际化,281行,modeDriven用来数据封装的,282行fileUpload,上传下载的,285行staticParams用来获取

      静态参数的,287行params用做数据封装的,290行conversionError标识数据类型转换异常处理的,291行,validation用来做输入校验的 292行workflow用来

      检测<filederror>是否有值,有值则跳到input结果码对应的页面。

      3)拦截器的执行时机

      

    二、自定义拦截器

      

      大多数功能的拦截器struts2都已经帮我们写好了,但是有一些,我们需要自己在往其中功能,那就必须自定义拦截器了。自定义拦截器很简单,就分两步即可:

        1)编写拦截器类,继承AbstractInterceptor类。(它帮我们实现了Interceptor接口)

        2)注册拦截器 

          在<package>声明拦截器

            在<action>中引用拦截器

      1).编写一个类,继承AbstractInterceptor类或者实现Interceptor接口。重写intercept方法。

        

      2)配置拦截器:注意拦截器必须先声明后使用

        

      3)测试拦截器的执行顺序

        访问:

          

        结果:

          

      4)多个拦截器的执行顺序

        struts.xml中的配置

        

        编写两个自定义拦截器

        

        执行结果:

        

      问题:一旦为Action指定了拦截器,那么就不会再为这个Action执行默认拦截器了,这个怎么解决?

        比如:

        

        上图所示一般不用这种,因为Struts2有这么一种机制,一旦为Action指定了拦截器,那么就不会再为这个Action执行默认拦截器了,即

        defaultStack这个拦截器栈中的拦截器都不会执行,也就是说,这个Action没有输入校验、没有参数注入、没有国际化、没有…,这是不

        行的,所以我们需要在这个<action>元素中再引用defaultStack拦截器栈

        

        这种虽然达到了我们的效果,但是非常麻烦,因为只有一个action,如果有十几个action呢?需要为每个action配置默认拦截器栈和自定义拦

        截器,所以使用最后一种方案。

        终极方案:创建一个拦截器栈,将默认拦截器栈和自定义拦截器加入其中,然后将struts2的默认拦截器栈修改为我们新构建的拦截器栈

        

    三、拦截器应用

      1)页面

        login.jsp

        

        main.jsp

        

        otherPage.jsp

        

      2)struts.xml

        

      3)Demo2Action.java

        

      4)checkLoginInterceptor.java拦截器

        

      5)测试

        因为我们用来测试的,所以我们在动作类中直接就给user赋值了,相当于就是登录了。

        

        然后跳转到主页

        

        点击另一个页面

        

    四、案例中的问题

      1)问题一:由于我们写了自己的拦截器,默认的拦截器就不起作用了。

       解决办法:把默认的拦截器加到配置文件中  

    <package name="p2" extends="struts-default">
            <interceptors>声明拦截器
                <interceptor name="checkLoginInterceptor" class="com.jxlg.web.interceptor.CheckLoginInterceptor" />
            </interceptors>
            <global-results>全局结果视图
                <result name="input">/login.jsp</result>数据回显的结果视图
            </global-results>
            用户登录时,不需要检查登录的拦截器工作
            <action name="login" class="com.jxlg.web.action.Demo2Action" method="login">
                <result type="redirectAction">showMain</result>
            </action>
            前往主页的动作名称,需要检查登录的拦截器工作
            <action name="showMain" class="com.jxlg.web.action.Demo2Action" >
                <interceptor-ref name="checkLoginInterceptor"></interceptor-ref>
                 <interceptor-ref name="defaultStack"></interceptor-ref>    
                <result>/main.jsp</result>
            </action>
            前往另一个页面的动作名称,需要检查登录的拦截器工作
            <action name="showOther" class="com.jxlg.web.action.Demo2Action" >
                <interceptor-ref name="checkLoginInterceptor"></interceptor-ref>
                <interceptor-ref name="defaultStack"></interceptor-ref>   
                <result>/otherpage.jsp</result>
            </action>
        </package>

      2)问题二:上面1中还是存在问题。当有多个拦截器时,需要改写的内容很多

        解决方法:抽取公共包,把全局配置放入公共包中

    <package name="p2" extends="struts-default">
            <interceptors>
                <interceptor name="checkLoginInterceptor" class="com.jxlg.web.interceptor.CheckLoginInterceptor" />
                定义一个拦截器栈,把我们自定义的拦截器和默认的拦截器栈放到一起.
                <interceptor-stack name="myDefaultStack">
                    <interceptor-ref name="defaultStack"></interceptor-ref>
                    <interceptor-ref name="checkLoginInterceptor"></interceptor-ref>
                </interceptor-stack>
            </interceptors>
            <global-results>
                <result name="input">/login.jsp</result>
            </global-results>
            <action name="login" class="com.jxlg.web.action.Demo2Action" method="login">
                <result type="redirectAction">showMain</result>
            </action>
            <action name="showMain" class="com.jxlg.web.action.Demo2Action" >
                直接引入我们自己定义的拦截器栈,里面已经包含了默认的拦截器栈
                <interceptor-ref name="myDefaultStack"></interceptor-ref>
                <result>/main.jsp</result>
            </action>
            <action name="showOther" class="com.jxlg.web.action.Demo2Action" >
                直接引入我们自己定义的拦截器栈,里面已经包含了默认的拦截器栈
                <interceptor-ref name="myDefaultStack"></interceptor-ref>
                <result>/otherpage.jsp</result>
            </action>
        </package>
    
    struts.xml

      3)问题:还要在每个动作方法中引入自定义的拦截器栈,能不能不用呢?

       解决方法:我们在设置【开发模式】时,覆盖掉了一个default.properties中的常量,能不能把struts-default.xml中的默认拦截器栈的设置给覆盖掉呢?答案是可以的。 

       

    <package name="p2" extends="struts-default">
            <interceptors>
                <interceptor name="checkLoginInterceptor" class="com.jxlg.web.interceptor.CheckLoginInterceptor" />
                <interceptor-stack name="myDefaultStack">
                    <interceptor-ref name="defaultStack"></interceptor-ref>
                    <interceptor-ref name="checkLoginInterceptor"></interceptor-ref>
                </interceptor-stack>
            </interceptors>
            覆盖了struts-default.xml中定义的默认拦截器栈。由myDefaultStack把defaultStack给替换了
            <default-interceptor-ref name="myDefaultStack"></default-interceptor-ref>
            <global-results>
                <result name="input">/login.jsp</result>
            </global-results>
            <action name="login" class="com.jxlg.web.action.Demo2Action" method="login">
                <result type="redirectAction">showMain</result>
            </action>
            <action name="showMain" class="com.jxlg.web.action.Demo2Action" >
                <result>/main.jsp</result>
            </action>
            <action name="showOther" class="com.jxlg.web.action.Demo2Action" >
                <result>/otherpage.jsp</result>
            </action>
        </package>
    

      4)问题:当使用默认的拦截器栈,这时候三个动作都会被检查登录拦截。但是我们第一个动作方法login()不需要拦截器呀?

        解决方法:需要通过AbstractInterceptor类的子类入手,通过查看发现,该类还有一个子类是抽象的。

        

        在AbstractInterceptor的子类中,还有一个抽象类MethodFilterInterceptor,它里面提供了两个属性
            excludeMethods:哪些方法不需要拦截
            includeMethods:哪些方法需要拦截

        

        

        重新写拦截器类,这次我们继承MethodFilterInterceptor

    package com.itheima.web.interceptor;
    
    import javax.servlet.http.HttpSession;
    
    import org.apache.struts2.ServletActionContext;
    
    import com.opensymphony.xwork2.ActionInvocation;
    import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
    /**
     * 检查登录的拦截器,最终版本
     * @author zhy
     *
     */
    public class CheckLoginInterceptor1 extends MethodFilterInterceptor {
    
        public String doIntercept(ActionInvocation invocation) throws Exception {
            //1.获取HttpSession
            HttpSession session = ServletActionContext.getRequest().getSession();
            //2.获取session域中的登录标记
            Object obj = session.getAttribute("user");
            //3.判断是否有登录标记
            if(obj == null){
                //用户没有登录
                return "input";
            }
            //4.用户登录了,放行
            String rtValue = invocation.invoke();
            return rtValue;
        }
    
    }

      并且在struts的配置文件中,配置需要拦截哪些方法,和需要放过哪些方法。

    <package name="p2" extends="struts-default">
            <interceptors>
                <interceptor name="checkLoginInterceptor1" class="com.jxlg.web.interceptor.CheckLoginInterceptor1" />
                <interceptor-stack name="myDefaultStack">
                    <interceptor-ref name="defaultStack"></interceptor-ref>
                    <interceptor-ref name="checkLoginInterceptor1">
                        给自定义拦截器注入参数,告知他哪些方法不需要拦截
                        <param name="excludeMethods">login</param>
                    </interceptor-ref>
                </interceptor-stack>
            </interceptors>
            <default-interceptor-ref name="myDefaultStack"></default-interceptor-ref>
            <global-results>
                <result name="input">/login.jsp</result>
            </global-results>
            <action name="login" class="com.jxlg.web.action.Demo2Action" method="login">
                <result type="redirectAction">showMain</result>
            </action>
            <action name="showMain" class="com.jxlg.web.action.Demo2Action" >
                <result>/main.jsp</result>
            </action>
            <action name="showOther" class="com.jxlg.web.action.Demo2Action" >
                <result>/otherpage.jsp</result>
            </action>
        </package>
    
    struts.xml

      5)问题:我们在声明时配置了哪些方法需要拦截,哪些方法不需要拦截。但是在没有写动作类和动作方法之前,不确定方法名叫什么。

        解决方法:我们需要在使用拦截器的时候给它注入参数。告诉拦截器哪些需要拦截,哪些不需要

    package name="p2" extends="struts-default">
            <interceptors>
                <interceptor name="checkLoginInterceptor1" class="com.jxlg.web.interceptor.CheckLoginInterceptor1" />
                <interceptor-stack name="myDefaultStack">
                    <interceptor-ref name="defaultStack"></interceptor-ref>
                    <interceptor-ref name="checkLoginInterceptor1"></interceptor-ref>
                </interceptor-stack>
            </interceptors>
            <default-interceptor-ref name="myDefaultStack"></default-interceptor-ref>
            <global-results>
                <result name="input">/login.jsp</result>
            </global-results>
            
            <action name="login" class="com.jxlg.web.action.Demo2Action" method="login">
                <interceptor-ref name="myDefaultStack">
                    <!-- 在引用自定义拦截器栈的时候,给指定的拦截器注入参数。方式就是:拦截器名称.属性名称 -->
                    <param name="checkLoginInterceptor1.excludeMethods">login</param>
                </interceptor-ref>
                <result type="redirectAction">showMain</result>
            </action>
            <action name="showMain" class="com.jxlg.web.action.Demo2Action" >
                <result>/main.jsp</result>
            </action>        
            <action name="showOther" class="com.jxlg.web.action.Demo2Action" >
                <result>/otherpage.jsp</result>
            </action>
        </package>
    
    struts.xml

      所以在以后的开发中就都是用这种形式

      

      

     喜欢就“推荐”哦!

  • 相关阅读:
    Docker构建Centos7容器
    Docker命令大全
    win10常用开发配置
    git小结
    JSP页面The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path错误处理
    CentOS 设置mysql的远程访问
    CentOS安装MySQL
    Kali对wifi的破解记录
    MyEclipse对Maven的安装
    关于sqlmap的使用
  • 原文地址:https://www.cnblogs.com/zhangyinhua/p/7777355.html
Copyright © 2011-2022 走看看