关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » JAVA »Java Struts 实现拦截器

    Java Struts 实现拦截器

    2015-03-31 00:00:00 出处:ImportNew
    分享

    Struts2的拦截器和Servlet过滤器类似。在执行Action的execute方法之前,Struts2会首先执行在struts.xml中引用的拦截器,在执行完所有引用的拦截器的intercept方法后,会执行Action的execute方法。

    Struts2拦截器类必须从com.opensymphony.xwork2.interceptor.Interceptor接口继承,在Intercepter接口中有如下三个方法需要实现:

    void destroy();
    void init();
    String intercept(ActionInvocation invocation) throws Exception;

    其中intercept方法是拦截器的核心方法,所有安装的拦截器都会调用之个方法。在Struts2中已经在struts-default.xml中预定义了一些自带的拦截器,如timer、params等。如果在<package>标签中继承struts-default,则当前package就会自动拥有struts-default.xml中的所有配置。代码如下:

    <package name=”demo” extends=”struts-default” > … </package>

    在struts-default.xml中有一个默认的引用,在默认情况下(也就是<action>中未引用拦截器时)会自动引用一些拦截器。这个默认的拦截器引用如下:

    <default-interceptor-ref name="defaultStack"/>
    
    <interceptor-stack name="defaultStack">   
        <interceptor-ref name="exception"/>
        <interceptor-ref name="alias"/>
        <interceptor-ref name="servletConfig"/>
        <interceptor-ref name="prepare"/>
        <interceptor-ref name="i18n"/>
        <interceptor-ref name="chain"/>
        <interceptor-ref name="debugging"/>
        <interceptor-ref name="profiling"/>
        <interceptor-ref name="scopedModelDriven"/>
        <interceptor-ref name="modelDriven"/>
        <interceptor-ref name="fileUpload"/>
        <interceptor-ref name="checkbox"/>
        <interceptor-ref name="staticParams"/>
        <interceptor-ref name="params">
            <param name="excludeParams">dojo/..*</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-stack>

    上面在defaultStack中引用的拦截器都可以在<action>中不经过引用就可以使用(如果在<action>中引用了任何拦截器后,要使用在defaultStack中定义的拦截器,也需要在<action>中重新引用,在后面将详细讲解)。

    下面我们来看几个简单的拦截器的使用方法。

    一、记录拦截器和execute方法的执行时间(timer)

    timer是Struts2中最简单的拦截器,这个拦截器对应的类是com.opensymphony.xwork2.interceptor.TimerInterceptor。它的功能是记录execute方法和其他拦截器(在timer后面定义的拦截器)的intercept方法执行的时间总和。如下面的配置代码所示:

    <action name="first" class="action.FirstAction">
        <interceptor-ref name="logger"/>
        <interceptor-ref name="timer" />
    </action>

    由于在timer后面没有其他的拦截器定义,因此,timer只能记录execute方法的执行时间,在访问first动作时,会在控制台输出类似下面的一条信息:

    信息: Executed action [/test/first!execute] took 16 ms.

    在使用timer拦截器时,需要commons-logging.jar的支持。将logger引用放到timer的后面,就可以记录logger拦截器的intercept方法和Action的execute方法的执行时间总和,代码如下:

    <action name="first" class="action.FirstAction">
        <interceptor-ref name="timer" />
        <interceptor-ref name="logger"/>
    </action>

    大家可以使用如下的Action类来测试一下timer拦截器:

    package action;
    
    import com.opensymphony.xwork2.ActionSupport;
    
    public class FirstAction extends ActionSupport          
    
    {
           public String execute() throws Exception
    
           {
               Thread.sleep(1000); // 延迟1秒
               return null;
           }
    
    }

    如果只记录execute方法的执行时间,一般会输出如下的信息:

    信息: Executed action [/test/first!execute] took 1000 ms.

    二、通过请求调用Action的setter方法(params)

    当客户端的一个form向服务端提交请求时,如有一个textfield,代码如下:

    <s:form action="first" namespace="/test">
       <s:textfield name="name"/>
       <s:submit/>
    </s:form>

    在提交后,Struts2将会自动调用first动作类中的setName方法,并将name文本框中的值通过setName方法的参数传入。实际上,这个操作是由params拦截器完成的,params对应的类是com.opensymphony.xwork2.interceptor.ParametersInterceptor。由于params已经在defaultStack中定义,因此,在未引用拦截器的<action>中是会自动引用params的,如下面的配置代码,在访问first动作时,Struts2是会自动执行相应的setter方法的。

    <action name="first" class="action.FirstAction">
        ... ...
    </action>

    但如果在<action>中引用了其他的拦截器,就必须再次引用params拦截器,Struts2才能调用相应的setter方法。如下面的配置代码所示:

    <action name="first" class="action.FirstAction">
        <interceptor-ref name="timer" />
        <interceptor-ref name="params"/>
    </action>

    三、通过配置参数调用Action的setter方法(static-params)

    static-params拦截器可以通过配置<params>标签来调用Action类的相应的setter方法,static-params拦截器对应的类是com.opensymphony.xwork2.interceptor.StaticParametersInterceptor。
    下面配置代码演示了如何使用static-params拦截器:

    <action name="first" class="action.FirstAction">
        <interceptor-ref name="timer" />
        <param name="who">比尔</param>
        <interceptor-ref name="params"/>
        <interceptor-ref name="static-params"/>
    </action>

    如果first动作使用上面的配置,在访问first动作时,Struts2会自动调用setWho方法将“比尔”作为参数值传入setWho方法。

    四、使用拦截器栈

    为了能在多个动作中方便地引用同一个或几个拦截器,可以使用拦截器栈将这些拦截器作为一个整体来引用。拦截器栈要在<package>标签中使用<interceptors>和子标签<interceptor-stack>来定义。代码如下:

    <package name="demo" extends="struts-default" >
        <interceptors>
            <interceptor-stack name="mystack">
                <interceptor-ref name="timer" />
                <interceptor-ref name="logger" />
                <interceptor-ref name="params" />
                <interceptor-ref name="static-params" />
            </interceptor-stack>
        </interceptors>
    
        <action name="first" class="action.FirstAction">
            <param name="who">比尔</param>
            <interceptor-ref name="mystack"/>            
        </action>
    </package>

    可以象使用拦截器一样使用拦截器栈,如上面代码所示。

    拦截器的实现

    实现一个拦截器非常简单。实际上,一个拦截器就是一个普通的类,只是这个类必须实现com.opensymphony.xwork2.interceptor.Interceptor接口。Interceptor接口有如下三个方法:

    public interface Interceptor extends Serializable 
    {
        void destroy();
        void init();
        String intercept(ActionInvocation invocation) throws Exception;
    }

    其中init和destroy方法只在拦截器加载和释放(都由Struts2自身处理)时执行一次。而intercept方法在每次访问动作时都会被调用。Struts2在调用拦截器时,每个拦截器类只有一个对象实例,而所有引用这个拦截器的动作都共享这一个拦截器类的对象实例,因此,在实现Interceptor接口的类中如果使用类变量,要注意同步问题。

    下面我们来实现一个简单的拦截器,这个拦截器通过请求参数action指定一个拦截器类中的方法,并调用这个方法(我们可以使用这个拦截器对某一特定的动作进行预处理)。如果方法不存在,或是action参数不存在,则继续执行下面的代码。如下面的URL:

    http://localhost:8080/struts2/test/interceptor.action action=test

    访问上面的url后,拦截器会就会调用拦截器中的test方法,如果这个方法不存在,则调用invocation.invoke方法,invoke方法和Servlet过滤器中调用FilterChain.doFilter方法类似,如果在当前拦截器后面还有其他的拦截器,则invoke方法就是调用后面拦截器的intercept方法,否则,invoke会调用Action类的execute方法(或其他的执行方法)。

    下面我们先来实现一个拦截器的父类ActionInterceptor。这个类主要实现了根据action参数值来调用方法的功能,代码如下:

    package interceptor;
    
    import com.opensymphony.xwork2.ActionInvocation;
    import com.opensymphony.xwork2.interceptor.Interceptor;
    import javax.servlet.http.*;
    import org.apache.struts2.*;
    
    public class ActionInterceptor implements Interceptor
    {
        protected final String INVOKE = "##invoke";
    
        public void destroy()
        {
            System.out.println("destroy");
        }
    
        public void init()
        {
            System.out.println("init");
        }
    
        public String intercept(ActionInvocation invocation) throws Exception
        {    
            HttpServletRequest request = ServletActionContext.getRequest();
            String action = request.getParameter("action");
            System.out.println(this.hashCode());
            if (action != null)
            {
                try
                {
                    java.lang.reflect.Method method = this.getClass().getMethod(action);
                    String result = (String)method.invoke(this);
                    if(result != null)
                    {
                        if(!result.equals(INVOKE))
                            return result;
                    }
                    else
                        return null;
                }
                catch (Exception e)
                {
                }
            }
            return invocation.invoke();
        }
    }

    从上面代码中的intercept方法可以看出,在调用action所指定的方法后,来判断返回值。可能发生的情况有三种:

    1.返回值为null,执行return null。

    2.返回值为INVOKE,执行return invockation.invoke()。

    3.其他情况,执行return result。 result表示指定方法的返回值,如上面代码所示。

    在实现完上面的拦截器父类后,任何继承于ActionInterceptor类的拦截器都可以自动根据action的参数值调用自身的相应方法。下面我们来实现一个拥有两个动作方法test和print的拦截器类。代码如下:

    package interceptor;
    
    import javax.servlet.http.HttpServletResponse;
    import org.apache.struts2.ServletActionContext;
    
    public class MultiMethodInterceptor extends ActionInterceptor
    {
        public String test() throws Exception
        {
            HttpServletResponse response = ServletActionContext.getResponse();
            response.getWriter().println("invoke test");
            return this.INVOKE;
        }
    
        public String print() throws Exception
        {
            HttpServletResponse response = ServletActionContext.getResponse();
            response.getWriter().println("invoke print");
    
            return null;
        }
    }

    test方法返回了INVOKE,因此,在执行完这个方法后,Struts2会接着调用其他拦截器的intercept方法或Action类的execute方法。而print方法在执行完后,只是返回了null,而不再调用其他的方法了,也就是访问如下的url时,动作的execute方法将不会执行:

    http://localhost:8080/struts2/test/ddd.action action=print

    下面我们来实现一个Action类,代码如下:

    package action;
    
    import org.apache.struts2.*;
    import com.opensymphony.xwork2.ActionSupport;
    
    public class InterceptorAction extends ActionSupport
    {
        public String abcd() throws Exception
        {
            ServletActionContext.getResponse().getWriter()
                    .println("invoke abcd");
            return null;
        }
    }

    在这个Action类中,只有一个abcd方法,实际上,这个方法相当于execute方法,在下面会设置动作的method属性为abcd。下面我们来在struts.xml中定义拦截器类和动作,代码如下:

    < xml version="1.0" encoding="UTF-8"  >
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">
    <struts>
        <package name="demo" extends="struts-default" namespace="/test">
            <interceptors>
                <interceptor name="method" class="interceptor.MultiMethodInterceptor" />
                    <interceptor-stack name="methodStack">
                        <interceptor-ref name="method" />
                        <interceptor-ref name="defaultStack" />
                    </interceptor-stack>
            </interceptors>
    
            <action name="interceptor" class="action.InterceptorAction" method="abcd">
                <interceptor-ref name="methodStack" />
            </action>
        </package>
    </struts>

    在配置上面的methodStack拦截器时要注意,最好在后面引用defaultStack,否则很多通过拦截器提供的功能将失去。

    OK,现在访问如下的URL:

    http://localhost:8080/struts2/test/ddd.action action=test

    在浏览器中将会出现如下的字符串:
    invoke test

    invoke abcd

    而如果访问http://localhost:8080/struts2/test/ddd.action action=print,将会只出现如下的字符串:
    invoke print

    大家可以看出,访问这个url时并没有调用abcd方法。如果随便指定的action值的话,则只调用abcd方法,如访问http://localhost:8080/struts2/test/ddd.action action=aaa,就只会输出invoke abcd。

    拦截器的参数

    我们在使用很多Struts2内置的拦截器时会发现有很多拦截器都带参数,当然。我们自己做的拦截器也可以加上同样的参数。有两个参数比较常用,这两个参数是includeMethods和excludeMethods,其中includeMethods指定了拦截器要调用的Action类的执行方法(默认是execute),也就是说,只有在includeMethods中指定的方法才会被Struts2调用,而excludeMethods恰恰相反,在这个参数中指定的执行方法不会被Struts2调用。如果有多个方法,中间用逗号(,)分隔。在Struts2中提供了一个抽象类来处理这两个参数。这个类如下:

    com.opensymphony.xwork2.interceptor.MethodFilterInterceptor

    如有继承于这个类的拦截器类都会自动处理includeMethods和excludeMethods参数,如下面的拦截器类所示:

    package interceptor;
    
    import com.opensymphony.xwork2.ActionInvocation;
    import com.opensymphony.xwork2.interceptor.*;
    
    public class MyFilterInterceptor extends MethodFilterInterceptor
    {
        private String name;
        public String getName()
        {
            return name;
        }
        public void setName(String name)
        {
            this.name = name;
        }
        @Override
        protected String doIntercept(ActionInvocation invocation) throws Exception
        {
            System.out.println("doIntercept");
            System.out.println(name);
            return invocation.invoke();
        }
    }

    MethodFilterInterceptor的子类需要实现doIntercept方法(相当于Interceptor的intercept方法),如上面代码所示。在上面的代码中还有一个name属性,是为了读取拦截器的name属性而设置的,如下面的配置代码所示:

    < xml version="1.0" encoding="UTF-8"  >
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">
    <struts>
        <package name="demo" extends="struts-default" namespace="/test">
            <interceptors>
                <interceptor name="method" class="interceptor.MultiMethodInterceptor" />
                    <interceptor name="filter"
                        class="interceptor.MyFilterInterceptor">
                        <param name="includeMethods">abcd</param>
                        <param name="name">中国</param>
                    </interceptor>
                    <interceptor-stack name="methodStack">
                        <interceptor-ref name="method" />
                        <interceptor-ref name="filter" />
                        <interceptor-ref name="defaultStack" />
                    </interceptor-stack>
            </interceptors>
    
            <action name="interceptor" class="action.InterceptorAction" method="abcd">
                <interceptor-ref name="methodStack" />
            </action>
        </package>
    </struts>

    再次访问http://localhost:8080/struts2/test/ddd.action action=test, Struts2就会调用MyFilterInterceptor的doIntercept方法来输出name属性值。如果将上面的includeMethods参数值中的abcd去掉,则Action类的abcd方法不会被执行。

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    正版 Windows 11产品密钥怎么查找/查看?

    还有3个月,微软将停止 Windows 10 的更新

    Windows 10 终止支持后,企业为何要立即升级?

    Windows 10 将于 2025年10 月终止技术支持,建议迁移到 Windows 11

    Windows 12 发布推迟,微软正全力筹备Windows 11 25H2更新

    Linux 退出 mail的命令是什么

    Linux 提醒 No space left on device,但我的空间看起来还有不少空余呢

    hiberfil.sys文件可以删除吗?了解该文件并手把手教你删除C盘的hiberfil.sys文件

    Window 10和 Windows 11哪个好?答案是:看你自己的需求

    盗版软件成公司里的“隐形炸弹”?老板们的“法务噩梦” 有救了!

    IT头条

    公安部:我国在售汽车搭载的“智驾”系统都不具备“自动驾驶”功能

    02:03

    液冷服务器概念股走强,博汇、润泽等液冷概念股票大涨

    01:17

    亚太地区的 AI 驱动型医疗保健:2025 年及以后的下一步是什么?

    16:30

    智能手机市场风云:iPhone领跑销量榜,华为缺席引争议

    15:43

    大数据算法和“老师傅”经验叠加 智慧化收储粮食尽显“科技范”

    15:17

    技术热点

    商业智能成CIO优先关注点 技术落地方显成效(1)

    用linux安装MySQL时产生问题破解

    JAVA中关于Map的九大问题

    windows 7旗舰版无法使用远程登录如何开启telnet服务

    Android View 事件分发机制详解

    MySQL用户变量的用法

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。