首页 > 代码库 > struts2 拦截器

struts2 拦截器

Struts2中的拦截器(特别重要)

      1、拦截器的重要性

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

                     AOP编程思想的一种应用形式。

      2、拦截器的执行时机:

                    技术分享

 

      3、自定义拦截器

           3.1、拦截器的类试图(初级版本):

        技术分享

 

           3.2、编写步骤:

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

技术分享
 1 package com.itheima.web.interceptor;
 2 
 3 import com.opensymphony.xwork2.ActionInvocation;
 4 import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
 5 /**
 6  * 自定义拦截器
 7  *     第一步:创建一个普通类,继承AbstractInterceptor,实现抽象方法intercept
 8  *  第二步:在struts.xml中配置拦截器
 9  *       1.声明拦截器
10  *          <interceptors>
11                 <interceptor name="demo1Interceptor" class="com.itheima.web.interceptor.Demo1Interceptor" />
12             </interceptors>
13          2.使用拦截器
14              <!-- 使用自定义拦截器:当配置了任何一个拦截器,默认的拦截器栈就不会在工作了 -->
15             <interceptor-ref name="demo1Interceptor"></interceptor-ref>
16  * @author zhy
17  *
18  */
19 public class Demo1Interceptor extends AbstractInterceptor {
20 
21     public String intercept(ActionInvocation invocation) throws Exception {
22         System.out.println("Demo1Interceptor拦截器:拦截了-执行动作方法之前");
23         //放行:如果有下一个拦截器,就前往下一个拦截器,如果没有了,就到达动作方法
24         String rtValue = http://www.mamicode.com/invocation.invoke();//就是结果视图的名称
25         System.out.println("Demo1Interceptor拦截器:拦截了-执行动作方法之后");
26         return rtValue;
27     }
28 
29 }
MyInterceptor1

                     b、配置拦截器:注意拦截器必须先声明再使用

                 注意: 在xml中配置了任何一个拦截器,默认的拦截器就不会再给我们工作了,要重新配置

技术分享
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE struts PUBLIC
 3     "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
 4     "http://struts.apache.org/dtds/struts-2.3.dtd">
 5 <struts>
 6     <constant name="struts.devMode" value="true" />
 7     <package name="p1" extends="struts-default">
 8         <!-- 声明自定义拦截器 -->
 9         <interceptors>
10             <interceptor name="demo1Interceptor" class="com.itheima.web.interceptor.Demo1Interceptor"></interceptor>
11             <interceptor name="demo2Interceptor" class="com.itheima.web.interceptor.Demo2Interceptor"></interceptor>
12         </interceptors>
13         <action name="action1" class="com.itheima.web.action.Demo1Action" method="save">
14             <!-- 使用自定义拦截器:当配置了任何一个拦截器,默认的拦截器栈就不会在工作了 .
15                 当有多个拦截器的时候,是由引用配置决定执行的顺序 。 注意:执行顺序与声明无关-->
16             <interceptor-ref name="demo2Interceptor"></interceptor-ref>
17             <interceptor-ref name="demo1Interceptor"></interceptor-ref>
18             <result name="success">/demo1.jsp</result>
19         </action>
20     </package>
struts.xml

 

           3.3、执行顺序

                          见前面的执行时机图

           3.4、多个拦截器的执行顺序

                    在动作方法执行之前, 拦截器执行顺序与配置(不是声明)顺序正相关

       在动作方法执行之后, 拦截器执行顺序与配置(不是声明 )顺序负相关

           3.5、intercept方法的返回值

                       return      invocation.invoke();   返回的就是 结果视图(seccess,input,error等)

      4、拦截器的应用:

            4.1、检查登录的拦截器案例

                      配置文件:

                    

技术分享
 1 <!-- 使用自定义拦截器,检查登录。最基本的配置方式。
 2          其中存在的问题:
 3              当我们使用了自定义拦截器之后,默认的拦截器栈就不再工作了 -->
 4     <package name="p2" extends="struts-default">
 5         <interceptors>声明拦截器
 6             <interceptor name="checkLoginInterceptor" class="com.itheima.web.interceptor.CheckLoginInterceptor" />
 7         </interceptors>
 8         <global-results>全局结果视图
 9             <result name="input">/login.jsp</result>数据回显的结果视图
10         </global-results>
11         用户登录时,不需要检查登录的拦截器工作
12         <action name="login" class="com.itheima.web.action.Demo2Action" method="login">
13             <result type="redirectAction">showMain</result>
14         </action>
15         前往主页的动作名称,需要检查登录的拦截器工作
16         <action name="showMain" class="com.itheima.web.action.Demo2Action" >
17             <interceptor-ref name="checkLoginInterceptor"></interceptor-ref>
18             <result>/main.jsp</result>
19         </action>
20         前往另一个页面的动作名称,需要检查登录的拦截器工作
21         <action name="showOther" class="com.itheima.web.action.Demo2Action" >
22             <interceptor-ref name="checkLoginInterceptor"></interceptor-ref>
23             <result>/otherpage.jsp</result>
24         </action>
25     </package>
struts.xml

 

                     动作类:

                          

技术分享
 1 package com.itheima.web.action;
 2 
 3 import javax.servlet.http.HttpSession;
 4 
 5 import org.apache.struts2.ServletActionContext;
 6 
 7 import com.opensymphony.xwork2.ActionSupport;
 8 
 9 public class Demo2Action extends ActionSupport {
10     
11     
12     /**
13      * 用户登录的方法
14      * @return
15      */
16     public String login(){
17         HttpSession session = ServletActionContext.getRequest().getSession();
18         session.setAttribute("user", "test");
19         return SUCCESS;
20     }
21     
22 
23     
24     /**
25      * 无论是显示主页还是显示另一个页面都执行此方法,
26      * 返回成功
27      */
28     public String execute(){
29         return SUCCESS;
30     }
31 }
动作类

 

                     拦截器:

                        

技术分享
 1 package com.itheima.web.interceptor;
 2 
 3 import javax.servlet.http.HttpSession;
 4 
 5 import org.apache.struts2.ServletActionContext;
 6 
 7 import com.opensymphony.xwork2.ActionInvocation;
 8 import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
 9 /**
10  * 检查登录的拦截器,初级版本
11  * @author zhy
12  *
13  */
14 public class CheckLoginInterceptor extends AbstractInterceptor {
15 
16     public String intercept(ActionInvocation invocation) throws Exception {
17         //1.获取HttpSession
18         HttpSession session = ServletActionContext.getRequest().getSession();
19         //2.获取session域中的登录标记
20         Object obj = session.getAttribute("user");
21         //3.判断是否有登录标记
22         if(obj == null){
23             //用户没有登录
24             return "input";
25         }
26         //4.用户登录了,放行
27         String rtValue =http://www.mamicode.com/ invocation.invoke();
28         return rtValue;
29     }
30 
31 }
拦截器,形式1

 

                     页面:

                    

技术分享
 1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 2 
 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 4 <html>
 5     <head>
 6         <title>主页:检查登录的拦截器</title>
 7     </head>
 8     <body>
 9         <%--要想来到本页面(主页),必须得先登录 --%>
10         主页<hr/>
11         <a href="${pageContext.request.contextPath}/showOther.action">访问另一个页面</a>
12     </body>
13 </html>
主页
技术分享
 1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 2 
 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 4 <html>
 5     <head>
 6         <title>用户登录</title>
 7     </head>
 8     <body>
 9         <form action="${pageContext.request.contextPath}/login.action" method="post">
10             用户名:<input type="text" name="username"/><br/>
11             密码:<input type="password" name="password"/><br/>
12             <input type="submit" value="登录"/>
13         </form>
14     </body>
15 </html>
login
技术分享
 1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 2 
 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 4 <html>
 5     <head>
 6         <title>另一个页面</title>
 7     </head>
 8     <body>
 9         另一个页面
10     </body>
11 </html>
otherpage

 

           4.2、案例中的问题

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

                     解决办法:

                            a、把默认拦截器加入到配置文件中

                           

技术分享
 1 <!-- a.针对上面的问题,我们的解决办法是,把默认的拦截器栈也配置进来.
 2     <package name="p2" extends="struts-default">
 3         <interceptors>
 4             <interceptor name="checkLoginInterceptor" class="com.itheima.web.interceptor.CheckLoginInterceptor" />
 5         </interceptors>
 6         <global-results>
 7             <result name="input">/login.jsp</result>
 8         </global-results>
 9         <action name="login" class="com.itheima.web.action.Demo2Action" method="login">
10             <result type="redirectAction">showMain</result>
11         </action>
12         <action name="showMain" class="com.itheima.web.action.Demo2Action" >
13             加入自定义拦截器,和默认的拦截器栈
14             <interceptor-ref name="defaultStack"></interceptor-ref>
15             <interceptor-ref name="checkLoginInterceptor"></interceptor-ref>
16             <result>/main.jsp</result>
17         </action>
18         <action name="showOther" class="com.itheima.web.action.Demo2Action" >
19             加入自定义拦截器,和默认的拦截器栈
20             <interceptor-ref name="defaultStack"></interceptor-ref>
21             <interceptor-ref name="checkLoginInterceptor"></interceptor-ref>
22             <result>/otherpage.jsp</result>
23         </action>
24     </package>-->
struts.xml

 

                     ba中暴露的问题:当有多个拦截器时,需要改写的地方非常多。

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

                    

技术分享
 1 <!-- b. a中存在的弊端,当如果需要拦截的动作很多时,写起来很繁琐
 2     <package name="p2" extends="struts-default">
 3         <interceptors>
 4             <interceptor name="checkLoginInterceptor" class="com.itheima.web.interceptor.CheckLoginInterceptor" />
 5             定义一个拦截器栈,把我们自定义的拦截器和默认的拦截器栈放到一起.
 6             <interceptor-stack name="myDefaultStack">
 7                 <interceptor-ref name="defaultStack"></interceptor-ref>
 8                 <interceptor-ref name="checkLoginInterceptor"></interceptor-ref>
 9             </interceptor-stack>
10         </interceptors>
11         <global-results>
12             <result name="input">/login.jsp</result>
13         </global-results>
14         <action name="login" class="com.itheima.web.action.Demo2Action" method="login">
15             <result type="redirectAction">showMain</result>
16         </action>
17         <action name="showMain" class="com.itheima.web.action.Demo2Action" >
18             直接引入我们自己定义的拦截器栈,里面已经包含了默认的拦截器栈
19             <interceptor-ref name="myDefaultStack"></interceptor-ref>
20             <result>/main.jsp</result>
21         </action>
22         <action name="showOther" class="com.itheima.web.action.Demo2Action" >
23             直接引入我们自己定义的拦截器栈,里面已经包含了默认的拦截器栈
24             <interceptor-ref name="myDefaultStack"></interceptor-ref>
25             <result>/otherpage.jsp</result>
26         </action>
27     </package> -->
28     
29     <!-- c. b中存在的问题,还需要在每个要用到地方使用拦截器引用。
30          解决办法:使用覆盖struts-default.xml配置文件中的默认拦截器栈,让我们的这个称为默认的-->
31     
32     <package name="p2" extends="struts-default">
33         <interceptors>
34             <interceptor name="checkLoginInterceptor" class="com.itheima.web.interceptor.CheckLoginInterceptor" />
35             <interceptor-stack name="myDefaultStack">
36                 <interceptor-ref name="defaultStack"></interceptor-ref>
37                 <interceptor-ref name="checkLoginInterceptor"></interceptor-ref>
38             </interceptor-stack>
39         </interceptors>
40         覆盖了struts-default.xml中定义的默认拦截器栈。由myDefaultStack把defaultStack给替换了
41         <default-interceptor-ref name="myDefaultStack"></default-interceptor-ref>
42         <global-results>
43             <result name="input">/login.jsp</result>
44         </global-results>
45         <action name="login" class="com.itheima.web.action.Demo2Action" method="login">
46             <result type="redirectAction">showMain</result>
47         </action>
48         <action name="showMain" class="com.itheima.web.action.Demo2Action" >
49             <result>/main.jsp</result>
50         </action>
51         <action name="showOther" class="com.itheima.web.action.Demo2Action" >
52             <result>/otherpage.jsp</result>
53         </action>
54     </package> 
struts.xml

 

                     cb中的问题:还要再每个动作方法中引入拦截器。能不能不写呢?

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

          解决办法:

                    

技术分享
 1     <!-- c. b中存在的问题,还需要在每个要用到地方使用拦截器引用。
 2          解决办法:使用覆盖struts-default.xml配置文件中的默认拦截器栈,让我们的这个称为默认的 -->
 3     
 4     
 5     <package name="p2" extends="struts-default">
 6         <interceptors>
 7             <interceptor name="checkLoginInterceptor" class="com.itheima.web.interceptor.CheckLoginInterceptor" />
 8             <interceptor-stack name="myDefaultStack">
 9                 <interceptor-ref name="defaultStack"></interceptor-ref>
10                 <interceptor-ref name="checkLoginInterceptor"></interceptor-ref>
11             </interceptor-stack>
12         </interceptors>
13         覆盖了struts-default.xml中定义的默认拦截器栈。由myDefaultStack把defaultStack给替换了
14         <default-interceptor-ref name="myDefaultStack"></default-interceptor-ref>
15         <global-results>
16             <result name="input">/login.jsp</result>
17         </global-results>
18         <action name="login" class="com.itheima.web.action.Demo2Action" method="login">
19             <result type="redirectAction">showMain</result>
20         </action>
21         <action name="showMain" class="com.itheima.web.action.Demo2Action" >
22             <result>/main.jsp</result>
23         </action>
24         <action name="showOther" class="com.itheima.web.action.Demo2Action" >
25             <result>/otherpage.jsp</result>
26         </action>
27     </package>
struts.xml

 

                     dc中出现的问题:当使用了默认拦截器栈,这时候三个动作login,showIndex和show1Action都将被检查登录的拦截器拦截。

                            解决办法:

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

                                  

                                          所以我们在自定义拦截器时,还可以继承MethodFilterInterceptor并且重写doIntercept方法。

技术分享
 1 package com.itheima.web.interceptor;
 2 
 3 import javax.servlet.http.HttpSession;
 4 
 5 import org.apache.struts2.ServletActionContext;
 6 
 7 import com.opensymphony.xwork2.ActionInvocation;
 8 import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
 9 /**
10  * 检查登录的拦截器,最终版本
11  * @author zhy
12  *
13  */
14 public class CheckLoginInterceptor1 extends MethodFilterInterceptor {
15 
16     public String doIntercept(ActionInvocation invocation) throws Exception {
17         //1.获取HttpSession
18         HttpSession session = ServletActionContext.getRequest().getSession();
19         //2.获取session域中的登录标记
20         Object obj = session.getAttribute("user");
21         //3.判断是否有登录标记
22         if(obj == null){
23             //用户没有登录
24             return "input";
25         }
26         //4.用户登录了,放行
27         String rtValue =http://www.mamicode.com/ invocation.invoke();
28         return rtValue;
29     }
30 
31 }
MyInterceptor 2

 

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

         

技术分享
    <!-- d. c中存在的问题,当我们配置了默认的拦截器栈时,连登陆都被拦截了。
        解决办法: 在AbstractInterceptor的子类中,还有一个抽象类MethodFilterInterceptor,它里面提供了两个属性。
                excludeMethods:哪些方法不需要拦截
                includeMethods:哪些方法需要拦截 -->
     
    <package name="p2" extends="struts-default">
        <interceptors>
            <interceptor name="checkLoginInterceptor1" class="com.itheima.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.itheima.web.action.Demo2Action" method="login">
            <result type="redirectAction">showMain</result>
        </action>
        <action name="showMain" class="com.itheima.web.action.Demo2Action" >
            <result>/main.jsp</result>
        </action>
        <action name="showOther" class="com.itheima.web.action.Demo2Action" >
            <result>/otherpage.jsp</result>
        </action>
    </package>
struts.xml

 

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

                                   解决办法:我们需要在使用拦截器的时候给它注入参数。

                           

技术分享
 1 <!-- e. d中的问题,我们在声明拦截器和定义拦截器栈的时候,可能根本不知道哪些方法需要拦截,哪些不需要
 2         解决办法:在使用拦截器的时候,注入参数,告诉拦截器哪些需要拦截,哪些不需要
 3      -->
 4     <package name="p2" extends="struts-default">
 5         <interceptors>
 6             <interceptor name="checkLoginInterceptor1" class="com.itheima.web.interceptor.CheckLoginInterceptor1" />
 7             <interceptor-stack name="myDefaultStack">
 8                 <interceptor-ref name="defaultStack"></interceptor-ref>
 9                 <interceptor-ref name="checkLoginInterceptor1"></interceptor-ref>
10             </interceptor-stack>
11         </interceptors>
12         <default-interceptor-ref name="myDefaultStack"></default-interceptor-ref>
13         <global-results>
14             <result name="input">/login.jsp</result>
15         </global-results>
16         
17         <action name="login" class="com.itheima.web.action.Demo2Action" method="login">
18             <interceptor-ref name="myDefaultStack">
19                 <!-- 在引用自定义拦截器栈的时候,给指定的拦截器注入参数。方式就是:拦截器名称.属性名称 -->
20                 <param name="checkLoginInterceptor1.excludeMethods">login</param>
21             </interceptor-ref>
22             <result type="redirectAction">showMain</result>
23         </action>
24         <action name="showMain" class="com.itheima.web.action.Demo2Action" >
25             <result>/main.jsp</result>
26         </action>        
27         <action name="showOther" class="com.itheima.web.action.Demo2Action" >
28             <result>/otherpage.jsp</result>
29         </action>
30     </package>
struts.xml

 

           4.3、拦截器类视图(全):

                                     技术分享

lanjieqi

struts2 拦截器