代码江湖之勇闯天涯——struts2——拦截器的使用

“福伯,我来了,昨晚上回顾了一下前端时间的修炼,还有又自己看了一下国际化方向的资料,嘿嘿,又有学习修炼的冲动了。”
呵呵,好啊,那少爷,我们今天来学习拦截器的使用吧。在学习之前,我们先温习下之前讲到struts2的框架的时候的原理图,里边是不是有个Interceptor啊。是的,这就是struts2给我们封装了一些拦截器。当然我们也可以进行自定义的。
首先我们来看一下拦截器的运行图:


Interceptor

从图中我们可以看到,Interceptor的执行是在Action方法之前以及结果视图返回后执行,两次执行顺序是相反的。
从struts2的源码中我们可以了解到:



我们看到的所有的struts2为我们做好的拦截器,几乎都是继承与抽象类AbstractInterceptor,实现intercept方法。
那我们心里有数了,我们也按照里边走,继承抽象类实现方法,看看能不能做出一个自定义的拦截器,少爷,动手试试。
“好来,我来试试。”
首先创建一个类继承抽象类(继承AbstractInterceptor实现抽象方法intercept):
public class Demo1Interceptor extends AbstractInterceptor {

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        System.out.println("Demo1Interceptor拦截器执行ing");
        //放行
        String rtValue = invocation.invoke();//结果视图的名称
        System.out.println("Demo1Interceptor拦截器执行结束");
        System.out.println(rtValue);
        return rtValue;
    }

}

恩少爷,记住一定要invoke()进行放行,要不然无法向下传递了。
“之后呢,唔,我记得之前说配置框架及各种属性的时候说了一句要在struts.xml中进行配置,唔...”

    <!-- 声明自定义拦截器 -->
    <interceptors>
        <interceptor name="demo1Interceptor" class="com.wg.javaee.interceptor.Demo1Interceptor"></interceptor>
    </interceptors>

“不对啊,为什么还是没有结果,没有打印呢,福伯,你是不是说错啦~”
哈哈,少爷,你在仔细想想,你声明了拦截器,你有没有使用它啊,你要在哪使用它?
“嗯···,不知道了,福伯,你说吧,还差哪?”
嘿嘿,少爷也有不懂的时候啊,还差:

<action name="action1" class="com.wg.javaee.action.Demo1Action" method="save">
    <!-- 使用自定义拦截器,当配置了任意一个自定义拦截器,默认的拦截器栈就不会再工作了 
        当有多个拦截器时,执行顺序是interceptor-ref配置顺序
    -->
    <interceptor-ref name="demo1Interceptor"></interceptor-ref>
    <result name="success">/demo1.jsp</result>
</action>

好啦,运行一下,看看有什么变化没。


interceptor的执行顺序

从图中我们可以看到先执行了自定义拦截器,然后执行了动作方法,再到结果视图,再重新返回到自定义拦截器。
拦截器中的invoke()方法其实返回的就是结果视图的结果。

少爷,你现在会拦截器了,那我们来做一个小demo测试一下,要求:
1.有登陆页面。
2.有主页,但是只有在登陆之后才能进入。内部有个进入其他页面的链接。
3.有其他页,前提条件也是只有登陆之后才能查看。

操作ing···

“按照上边的步骤走,好了”

    <package name="p2" extends="struts-default">
        <!--声明拦截器-->
        <interceptors>
            <interceptor name="checkLoginInterceptor" class="com.wg.javaee.interceptor.CheckLoginInterceptor"/>
        </interceptors>
        <!--全局结果视图-->
        <global-results>
            <!--数据回显的结果视图-->
            <result name="input">/login.jsp</result>
        </global-results>
        <action name="login" class="com.wg.javaee.action.LoginAction" method="login">
            <result type="redirectAction">showMain</result>
        </action>
        <action name="showMain" class="com.wg.javaee.action.ShowMainAction">
            <interceptor-ref name="checkLoginInterceptor"/>
            <result>/main.jsp</result>
        </action>
        <action name="showOther" class="com.wg.javaee.action.ShowOtherAction">
            <interceptor-ref name="checkLoginInterceptor"/>
            <result>/other.jsp</result>
        </action>
    </package>

恩,少爷,果然聪明,可是你难道忘了么,当你设置了自己的拦截器的时候,默认的所有拦截器都会不起作用的。这样该怎么办?
“啊?真没有想那么多”
少爷,这要进行多次调整的:

1.使用正常的普通的设置拦截器

    <!-- a.使用自定义拦截,检查登录,最基本的配置 
         存在的问题:
            当我们使用了自定义拦截器之后,默认的拦截器栈不再工作了
    -->
    <package name="p2" extends="struts-default">
        <!--声明拦截器-->
        <interceptors>
            <interceptor name="checkLoginInterceptor" class="com.wg.javaee.interceptor.CheckLoginInterceptor"/>
        </interceptors>
        <!--全局结果视图-->
        <global-results>
            <!--数据回显的结果视图-->
            <result name="input">/login.jsp</result>
        </global-results>
        <action name="login" class="com.wg.javaee.action.LoginAction" method="login">
            <result type="redirectAction">showMain</result>
        </action>
        <action name="showMain" class="com.wg.javaee.action.ShowMainAction">
            <interceptor-ref name="checkLoginInterceptor"/>
            <result>/main.jsp</result>
        </action>
        <action name="showOther" class="com.wg.javaee.action.ShowOtherAction">
            <interceptor-ref name="checkLoginInterceptor"/>
            <result>/other.jsp</result>
        </action>
    </package>

此方式存在着弊端:我们无法使用默认的拦截器。

2.在1的基础上进行改进,我们引入默认的拦截器栈这样不就好了么

<!-- b.a中存在的弊端,当需要拦截的动作很多时,写起来繁琐 
    针对上边a的问题,我们的解决办法是,把默认的拦截器栈配置进来 <interceptor-ref name="defaultStack"></interceptor-ref> -->
    <package name="p2" extends="struts-default">
        <interceptors>
            <interceptor name="checkLoginInterceptor" class="com.wg.javaee.interceptor.CheckLoginInterceptor"/>
        </interceptors>
        <global-results>
            <result name="input">/login.jsp</result>
        </global-results>
        <action name="login" class="com.wg.javaee.action.LoginAction" method="login">
            <result type="redirectAction">showMain</result>
        </action>
        <action name="showMain" class="com.wg.javaee.action.ShowMainAction">
            <interceptor-ref name="defaultStack"/>
            <interceptor-ref name="checkLoginInterceptor"/>
            <result>/main.jsp</result>
        </action>
        <action name="showOther" class="com.wg.javaee.action.ShowOtherAction">
            <interceptor-ref name="defaultStack"/>
            <interceptor-ref name="checkLoginInterceptor"/>
            <result>/other.jsp</result>
        </action>
    </package>

此方式还是存在着弊端:我们需要在拦截的方法中进行不断的引用我们配置的所有拦截器

3.我们在2的基础上直接覆盖struts-default.xml配置文件的默认拦截栈,将原本的默认拦截栈和我们自己的拦截栈组合设置成新的默认拦截栈default-interceptor-ref

    <!-- c.b中存在的问题,还是需要在要用的地方使用拦截器引用
            解决办法:使用覆盖struts-default.xml配置文件中的默认拦截栈,让我们的这个成为默认的。
        在声明拦截器中定义一个interceptor-stack
    -->
    <package name="p2" extends="struts-default">
        <interceptors>
            <interceptor name="checkLoginInterceptor" class="com.wg.javaee.interceptor.CheckLoginInterceptor"/>
            <interceptor-stack name="myDefaultStack">
                <interceptor-ref name="defaultStack"></interceptor-ref>
                <interceptor-ref name="checkLoginInterceptor"></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.wg.javaee.action.LoginAction" method="login">
            <result type="redirectAction">showMain</result>
        </action>
        <action name="showMain" class="com.wg.javaee.action.ShowMainAction">
            <result>/main.jsp</result>
        </action>
        <action name="showOther" class="com.wg.javaee.action.ShowOtherAction">
            <result>/other.jsp</result>
        </action>
    </package>

然而这个方法还是有弊端... 当我们设置了新的默认拦截栈后发现,登陆的时候不想拦截都被拦截了,那我们就得看看有没有那种可以进行自己判断哪些方法需要拦截,哪些不需要拦截的。

4.我们通过观察源码,发现在AbstractInterceptor的子类中有个MethodFilterInterceptor,发现里边有俩参数有意思excludeMethods、includeMethods字面意思就是不包括的方法、包括的方法。那我们就可以使用参数注入的方式进行选择了

<!-- d.c中存在的问题,当我们配置了默认的拦截器栈后,不想拦截的也被拦截了
            解决办法:在AbstractInterceptor的子类中还有个抽象类MethodFilterInterceptor
            里边有两个属性  
            excludeMethods:哪些方法不需要拦截
            includeMethods:哪些方法需要拦截
     -->
    <package name="p2" extends="struts-default">
        <interceptors>
            <interceptor name="checkLoginInterceptor2" class="com.wg.javaee.interceptor.CheckLoginInterceptor2"/>
            <interceptor-stack name="myDefaultStack">
                <interceptor-ref name="defaultStack"></interceptor-ref>
                <interceptor-ref name="checkLoginInterceptor2">
                    注入的方式进行设置动作方法是否需要拦截 
                    <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.wg.javaee.action.LoginAction" method="login">
            <result type="redirectAction">showMain</result>
        </action>
        <action name="showMain" class="com.wg.javaee.action.ShowMainAction">
            <result>/main.jsp</result>
        </action>
        <action name="showOther" class="com.wg.javaee.action.ShowOtherAction">
            <result>/other.jsp</result>
        </action>
    </package>

但是,这种方法如果在我们先写拦截器的情况下,我们根部不知道哪些方法被拦截,哪些不被拦截,所以还是不方便

5千辛万苦揪出了最终格式,我们直接继承MethodFilterInterceptor,在不需要拦截的方法中使用params进行注入。

<!-- e.d中存在的问题,我们在声明拦截器和定义拦截器栈时,可能根本不知道哪些方法需要拦截哪些不需要
        解决办法,在使用拦截器的时候注入参数,告诉拦截器哪些需要拦截,哪些不需要
     -->
    <package name="p2" extends="struts-default">
        <interceptors>
            <interceptor name="checkLoginInterceptor2" class="com.wg.javaee.interceptor.CheckLoginInterceptor2"/>
            <interceptor-stack name="myDefaultStack">
                <interceptor-ref name="defaultStack"></interceptor-ref>
                <interceptor-ref name="checkLoginInterceptor2">
                </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.wg.javaee.action.LoginAction" method="login">
            <interceptor-ref name="myDefaultStack">
                <param name="checkLoginInterceptor2.excludeMethods">
                login
                </param>
            </interceptor-ref>
            <result type="redirectAction">showMain</result>
        </action>
        <action name="showMain" class="com.wg.javaee.action.ShowMainAction">
            <result>/main.jsp</result>
        </action>       
        <action name="showOther" class="com.wg.javaee.action.ShowOtherAction">
            <result>/other.jsp</result>
        </action>
    </package>

来吧少爷,运行一下项目试试。


demo演示

“哈哈哈,好有成就感,额,就是一步一步的推,好复杂啊。福伯,为什么你不一次性让我学最后一种啊,其他的也没用”
少爷,可不能这么说啊,你现在的一点一点的积累都是为你以后的强大做的基础的。如果不一步一步的推导,你会知道还有个拦截器抽象类叫MethodFilterInterceptor么。一步步的来你才会印象深刻啊。

“若林哥哥,过来陪灵儿玩好不好,无聊死了。啊,福伯也在啊,福伯,能不能让若林哥哥歇会陪我玩半天呀,嘿嘿。”
灵儿小姐,少爷才学了一点点,不好吧,struts2基础还没一半呢。
“好福伯啦,下次给你带灵泉酒好不好,反正若林哥哥也累了。嘿嘿”
怕了你了,就属你鬼灵精,去吧,早去早回啊。

未完待续哟···

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容