(六)Struts2的拦截器

一、简介

拦截器体系是struts2重要的组成部分。正是大量的内建拦截器完成了该框架的大部分操作。

比如params拦截器将请求参数解析出来,设置Action的属性。servletConfig拦截器负责将request和response对象传给Action的等等

拦截器可以动态的拦截发送到指定Action的请求,通过拦截器机制,我们可以在Action执行的前后插入某些代码。

通过这种方式,就可以把多个Action中重复的代码提取出来,放在拦截器中,从而提高更好的代码复用性。

 

理解DRY规则 DRY:               Don‘t Repeat Yourself 意思是不要书写重复的代码。

 

对于软件开发的新手来说,开发软件时可能很多地方需要重复性的功能和代码,新手会直接选择复制粘贴即可。

一旦需要更改维护这段代码,就要修改很多地方,后期的维护简直是噩梦。 所以有经验的开发人员会将重复代码定义成一个方法,哪里需要哪里调用即可,更改的时候只用修改方法即可。

 

二、拦截器的意义

上面的例子中当有一天代码中需要调用另一个方法,或者是代码中的方法需要经常切换。

这时候我们又得打开源码,修改所有调用方法的地方。造成这个问题的关键在于 以硬编码的方式调用方法。

为了解决这个问题,我们需要一种机制,所有代码中无需硬编码调用某个方法,但实际上又可以调用方法的功能。

struts2的拦截器就是实现了这种需求。拦截器会在目标方法调用之前之后调用一些方法。

 

三、拦截器的实现原理

拦截器基于AOP(面向切面编程)思想。 AOP编程方式中,有三个重要的概念

    -目标对象:被拦截方法的对象

    -被插入的处理方法:定义在拦截器中,会在被拦截方法之前、之后自动调用的方法。方法不能独立存在,必须有载体,载体就是拦截器,拦截器就是包含处理方法的实例。

    -代理对象:根据目标对象创建的代理对象。代理对象也称为AOP代理,系统动态生成一个对象,该对象将代替目标对象来使用。AOP代理包含了目标对象的所有方法,AOP代理中的方法会在特定位置插入拦截器方法,然后回调目标对象的处理方法,从而实现了执行目标方法之前或者之后调用拦截器方法。

 

四、struts2中的拦截器

 

Struts2框架拦截器

 

Struts 2框架提供了一个良好的开箱即用的拦截器列表,这些拦截器预先配置好并可以使用。 下面列出了几个重要的拦截器:

 

序号拦截器和说明
1alias

允许参数在请求之间使用不同的别名。

2checkbox

通过为未检查的复选框添加参数值false,以辅助管理复选框。

3conversionError

将字符串转换为参数类型的错误信息放置到action的错误字段中。

4createSession

自动创建HTTP会话(如果尚不存在)。

5debugging

为开发人员提供一些不同的调试屏幕。

6execAndWait

当action在后台执行时,将用户发送到中间的等待页面。

7exception

映射从action到结果抛出的异常,允许通过重定向自动处理异常。

8fileUpload

便于文件上传。

9

i18n

在用户会话期间跟踪选定的区域。

10logger

通过输出正在执行的action的名称提供简单的日志记录。

11params

设置action上的请求参数。

12prepare

这通常用于执行预处理工作,例如设置数据库连接。

13profile

允许记录action的简单分析信息。

14scope

在会话或应用程序范围内存储和检索action的状态。

15ServletConfig

提供可访问各种基于servlet信息的action。

16timer

以action执行时间的形式提供简单的分析信息。

17token

检查action的有效性,以防止重复提交表单。

18validation

提供action的验证支持。

 

你可以阅读Struts 2文档,了解上述拦截器的完整信息。接下来我们会告诉你如何在Struts应用程序中使用拦截器。

 

五、拦截器使用

(一)配置拦截器

            在struts.xml中定义拦截器 

            <interceptor name="拦截器名" class="拦截器类" />

            如果配置拦截器时需要传入拦截器参数,则需要使用param元素。

            <interceptor name="拦截器名" class="拦截器类" > 
                <param name="参数名">参数值</param>
                ....
            </interceptor> 


            还可以把多个拦截器组成拦截器栈 
            <interceptor-stack name="拦截器栈名">
                <interceptor-ref name="拦截器一"/>
                <interceptor-ref name="拦截器二"/>
                ....
            </interceptor-stack>  

(二)使用拦截器或拦截器栈  

  通过<intercept-ref name="拦截器名字" />使用拦截器

(三)自定义拦截器

实现自定义拦截器需要实现Interceptor接口
            该接口有三个方法
            -void init():拦截器实例化之后调用,只会执行一次,用于初始化资源 

            -void destory():拦截器销毁之前调用 

            -String intercept(ActionInvocation invoction)throws Exception:该方法是用户需要实现的拦截动作。 该方法的ActionInvocation包含了被拦截的action引用等所有数据,可以调用该参数的invoke方法放行,如果有下一个拦截器转到下一个拦截器,如果没有就转给Action类的方法。

            struts2提供了AbstractInterceptor类实现了Interceptor接口,我们只需要继承这个类即可。  

(四)举例:

第一步:实现拦截器:

            public class MyInterceptor extends AbstractInterceptor {
                public String intercept(ActionInvocation invocation) throws Exception {
                    System.out.println("拦截器执行:动作方法之前"); 
                    //放行
                    String result=invocation.invoke();
                    System.out.println("拦截器执行:动作方法之后");
                    return result;
                }
            } 

第二步:创建action类

                    public class Demo extends ActionSupport {
                        public String execute(){
                            System.out.println("执行动作类的execute方法");
                            return SUCCESS;
                        }
                    } 

第三步:配置struts.xml文件

                    <package name="demo1" extends="struts-default"> 
                        //定义拦截器
                        <interceptors>
                            <interceptor name="myinterceptor" class="com.cad.struts2.interceptor.MyInterceptor"></interceptor>
                        </interceptors> 

                        <action name="demo1" class="com.cad.struts2.action.Demo"> 
                            //action中使用拦截器,如果action使用了拦截器,则默认的拦截器栈就失效
                            <interceptor-ref name="myinterceptor"></interceptor-ref>
                            <result>/Demo.jsp</result>
                        </action>
                    </package>  

第四步:返回成功的jsp页面

                    <body>
                        demo1.jsp
                        <%System.out.println("demo1.jsp执行了"); %>
                    </body>  

输出结果:

                        拦截器之前
                        执行动作类的execute方法
                        demo1.jsp执行了
                        拦截器之后 

 

六、拦截器堆栈

你可以想象,为每个action配置的多个拦截器将很快变得极其难以管理。为此,拦截器使用拦截器堆栈进行管理。这里是直接从struts-default.xml文件展示的一个例子:

<interceptor-stack name="basicStack">
   <interceptor-ref name="exception"/>
   <interceptor-ref name="servlet-config"/>
   <interceptor-ref name="prepare"/>
   <interceptor-ref name="checkbox"/>
   <interceptor-ref name="params"/>
   <interceptor-ref name="conversionError"/>
</interceptor-stack>

 

上面的堆栈称为basicStack,可以如下所述在你的配置中使用,此配置节点放置在<package ... />节点下。<interceptor-ref ... />标签引用的是在当前拦截器堆栈之前配置的拦截器或拦截器堆栈。因此非常重要的是在配置初始拦截器和拦截器堆栈时,确保name在所有拦截器和拦截器堆栈配置中是唯一的。
我们已经学习了如何将拦截器应用到action中,而拦截器堆栈的应用也是类似的。事实上,使用的标签也是一样的:

 

 
<action name="hello" class="com.tutorialspoint.struts2.MyAction">
   <interceptor-ref name="basicStack"/>
   <result>view.jsp</result>
</action

上述的“basicStack”注册将完整注册hello action的所使用的六个拦截器。要注意的是,拦截器按照它们被配置的顺序执行。例如,在上面的例子中,exception将首先执行,第二个将是servlet-config等。

 

七、拦截指定方法的拦截器

默认情况下,我们为某个action定义了拦截器,则这个拦截器会拦截该Action的所有方法,如果我们只需要拦截指定方法,此时需要使用struts2拦截器的方法过滤特性。

struts2提供了一个和MethodFilterInterceptor类,该类是AbstractInterceptor的子类。 

该类重写了intercept方法,提供了一个doIntercept(ActionInvocation invocation)抽象方法。 

该类重写的intercept方法已经实现了对Action的拦截行为,通过回调doIntercept来完成具体的拦截逻辑。 

我们需要重写doIntercept方法来实现拦截逻辑。 

实现方法过滤的拦截器和普通的拦截器并没有太大区别,但是这个类中增加了两个方法。
        -public void setExcludeMethods(String excludeMethods):指定的方法都不会被拦截
        -public void setIncludeMethods(String includeMethods):指定的方法会被拦截

如果一个方法同时被这两个方法指定,则这个方法会被拦截。

 第一步:我们编写一个自定义拦截器:

                public class DemoIntercept extends MethodFilterInterceptor {


                    protected String doIntercept(ActionInvocation invocation) throws Exception {

                        System.out.println("拦截器执行:动作方法之前");
                        String result=invocation.invoke();
                        System.out.println("拦截器执行:动作方法之后");
                        return result;
                    }

                } 

第二步:在struts.xml中配置:

                    <action name="demo1" class="com.cad.struts2.action.Demo">
                        <interceptor-ref name="myinterceptor"> 
                            //设置不会被拦截的方法
                            <param name="excludeMethods">execute</param>
                            //设置被拦截的方法
                            <param name="includeMethods">login,regist</param>
                        </interceptor-ref>
                        <result>/Demo.jsp</result>
                    </action> 

  

  

 

 

八、拦截器小常识

(1)拦截器和struts2插件的关系

我们需要为struts2扩展新功能时,这时需要开发自己的拦截器,通常我们不可能去修改struts-default.xml文件

而通用功能的拦截器也不应该在某个指定的action中配置。这就需要在struts2插件的struts-plugin.xml文件中配置拦截器。

(2)配置默认拦截器

<default-interceptor-ref name="拦截器或者拦截器栈名"></default-interceptor-ref>

对于多个action都要使用的拦截器,避免了在多个action中重复指定拦截器。

(3)使用拦截器时配置参数

    <interceptor-ref name="myinterceptor">
                    <param name="参数名"></param>
    </interceptor-ref> 

    用拦截器时配置的参数如果和定义拦截器时配置的参数相同,那么会覆盖定义时的参数。

(4)覆盖拦截器栈里特定拦截器的参数

    有时候,action需要使用拦截器栈,当使用这个拦截器栈,又需要覆盖指定拦截器的参数。
    可以通过param来指定,name为 拦截器名字.参数名 

                    <interceptor-ref name="mystack">
                        <param name="myintercept.name">参数值</param>
                    </interceptor-ref>

(5)拦截器执行顺序  

invoke方法之前的动作谁排在前面谁执行。

invoke方法之后的动作谁排在后面先执行。

其实这是递归实现。 第一个拦截器执行完,调用invoke方法,如果有下一个拦截器,执行第二个拦截器,然后没有拦截器的话,就执行Action类中的方法,然后返回到第二个拦截器,第二个拦截器执行完毕,然后返回到第一个拦截器。  

例子:实现登录权限控制  

当我们访问main.jsp时,触发拦截器,如果没有登录,返回到登陆页面

第一步:先创建一个自定义拦截器:

       public class LoginInterceptor extends MethodFilterInterceptor {


            protected String doIntercept(ActionInvocation invocation) throws Exception { 
                //获取session,判断session中是否有用户
                HttpSession session=ServletActionContext.getRequest().getSession(); 

                //没用户返回到input页面
                Object obj=session.getAttribute("user");
                if(obj==null){
                    return "input";
                } 
                //有的话放行
                String result=invocation.invoke();
                return result;
            }

        } 

第二步:创建一个action类

            public class DemoAction extends ActionSupport { 

                //登陆方法,向session中设置
                public String login(){
                    HttpSession session=ServletActionContext.getRequest().getSession();
                    session.setAttribute("user", "user");
                    return SUCCESS;
                }
                public String execute() throws Exception {

                    return SUCCESS;
                }
            } 

第三步:配置我们的struts.xml文件

                <package name="demo8" extends="struts-default"> 
                    <!--定义拦截器-->
                    <interceptors>
                        <interceptor name="logininterceptor" class="com.cad.struts2.interceptor.LoginInterceptor"></interceptor>
                    </interceptors> 

                    <action name="login" class="com.cad.struts2.action.DemoAction" method="login">
                        <!--登陆成功,直接跳转到main页面-->
                        <result type="redirectAction">main</result>
                    </action>  

                    <!--执行main动作时,需要拦截器拦截-->
                    <action name="main" class="com.cad.struts2.action.DemoAction">
                        <result>/main.jsp</result>
                        <result name="input">/login.jsp</result> 
                        <!--使用默认拦截器和我们的拦截器-->
                        <interceptor-ref name="defaultStack"></interceptor-ref>
                        <interceptor-ref name="logininterceptor"></interceptor-ref>
                    </action>
                </package>

  

  

  

  

  

  

  

  

  

  

 

转载于:https://www.cnblogs.com/yuexiaoyun/p/9446316.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值