struts2:拦截器

拦截器(Interceptor)是Struts 2的核心组件,Struts 2框架的大部分功能都是通过拦截器来完成的,例如数据校验,国际化,文件上传和下载等。为了实现这些功能,Struts 2框架提供了一个强大的拦截器策略。

  • 拦截器是Struts 2框架中的重要组成部分,它是AOP(面向方向编程)思想的一种实现。使用拦截器给开发过程带来了很多好处:可以把大问题分解成多个小问题以便分别处理,同时可以使Action更专注于处理的事情,而把其他的一些相关功能分配给各个拦截器来进行处理。
  • 在Struts 2中可将各个功能应的拦截器分开定义,每个拦截器完成单个功能,如果要运用某个功能就加入对应的拦截器,实现了拦截器的可插拔式的设计,即这些拦截器可以自由选择,灵活的组合在一起形成拦截器链(Interceptor  Chain)或拦截器栈(Interceptor  Stack)。
  • 所谓拦截器链是指对应各个功能的拦截器组成的集合,它们按照一定的顺序排列在一起形成链,当有适配拦截器链访问的请求进来时,这些拦截器就会按照之前定义的顺序被调用。

使用Struts2拦截器

1. 配置拦截器

拦截器的配置是在struts.xml文件中完成的,拦截器通常使用<interceptor>标签来定义,该标签有两个属性name和class,分别用来指定拦截器名称及其实现类。

<interceptor name="interceptorName" class="interceptorClass">
        <param name="paramName">paramValue</param>
</interceptor>

2. 拦截器栈

  • 当开发的过程中需要定义多个拦截器时,可以将它们定义为一个拦截器栈。
  • 当一个拦截器栈被附加到一个Action上面时,在执行该Action之前,必须先执行拦截器栈中的每一个拦截器。
  • 使用拦截器栈不仅可以确定多个拦截器的执行顺序(拦截器栈中各个拦截器是按照其定义的顺序来执行的),同时,把相关的拦截器放在同一个栈中,管理起来也更为方便。
  • 定义拦截器栈需要用到<interceptor-stack>标签,该标签内包含了一系列的<interceptor-ref>子标签,这些子标签用来定义拦截器栈中包含的多个拦截器引用。
<package name="default" extends="struts-default" >
<interceptors>
       <!--定义两个拦截器,拦截器名分别为interceptor1和interceptor2-->
        <interceptor name="interceptor1" class=”interceptorClass”/>
        <interceptor name="interceptor2" class=”interceptorClass”/>
       <!--定义一个拦截器栈,拦截器包含了两个拦截器-->
        <interceptor-stack name="myStack">
          <interceptor-ref name="interceptor1"/>
          <interceptor-ref name="interceptor2"/>
        </interceptor-stack>
  </interceptors>
</package>

注意:在一个拦截器栈中也可以引用另一个拦截器栈。

3. 默认拦截器

  • 如果想对一个包下的多个Action使用相同的拦截器,则需要为该包中每个Action都重复指定同一个拦截器,显然过于繁琐,解决这个问题的方法就是使用默认拦截器。
  • 默认拦截器是指在一个包下定义的拦截器,该拦截器对包下所有的Action都起作用。
  • 一旦为某一个包指定了默认拦截器且该包中的Action未显式的指定拦截器,则该默认拦截器会起作用。反之,若此包中的Action显式指定了某个拦截器,则该默认拦截器被屏蔽,不会起作用,此时,若仍想使用默认拦截器,则需要用户手动配置该默认拦截器的引用。
  • 默认拦截器的配置需要使用<default-interceptor-ref>标签,在该标签中通过指定name属性来引用已经定义好的拦截器 。
  • 需要注意的是,每个包下只能定义一个默认拦截器。如果确实需要指定多个拦截器共同作为默认拦截器,则可以将这些拦截器定义为一个拦截器栈,再将这个拦截器栈配置成默认拦截器就可以了。
  • 实际上,拦截器类是定义在一个特殊的配置文件中的,这个配置文件就是struts-default.xml。当自定义包继承了struts-default默认包后,它不仅继承了其内置的各个拦截器,而且还继承了其默认拦截器栈,也就是说对于继承了struts-default包的某个自定义包下的所有的Action,struts-default包的默认拦截器栈会作用于所有这些Action。
<?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="default" extends="struts-default">
    <interceptors>
        <!--定义两个拦截器-->
        <interceptor name="interceptor1" class="interceptorClass"/>
        <interceptor name="interceptor2" class="interceptorClass"/>
        <!--定义一个拦截器栈-->
        <interceptor-stack name="myStack">
            <interceptor-ref name="interceptor1"/>
            <interceptor-ref name="interceptor2"/>
            <interceptor-ref name="defaultStack"/>
        </interceptor-stack>
    </interceptors>
    <!--配置包下的默认拦截器,既可以是拦截器,也可以是拦截器栈-->
    <default-interceptor-ref name="myStack"/>
    <action name="login" class="tutorial.Login">
        <result name="input">login.jsp</result>
    </action>
</package>
</struts>

struts-default.xml文件位于:struts2-core-2.3.x.jar文件中。包struts-default内容参考如下(摘录自struts-default.xml):

    <package name="struts-default" abstract="true">
        <result-types>
            <result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>
            <result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/>
            <result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/>
            <result-type name="httpheader" class="org.apache.struts2.dispatcher.HttpHeaderResult"/>
            <result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/>
            <result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/>
            <result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>
            <result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/>
            <result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/>
            <result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult" />
        </result-types>

        <interceptors>
            <interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
            <interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
            <interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>
            <interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>
            <interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/>
            <interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" />
            <interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" />
            <interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />
            <interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
            <interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
            <interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
            <interceptor name="i18n" class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/>
            <interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
            <interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
            <interceptor name="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/>
            <interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
            <interceptor name="actionMappingParams" class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/>
            <interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
            <interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>
            <interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/>
            <interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
            <interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/>
            <interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
            <interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>
            <interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
            <interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>
            <interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" />
            <interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" />
            <interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />
            <interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" />
            <interceptor name="annotationWorkflow" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor" />
            <interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" />

            <!-- Basic stack -->
            <interceptor-stack name="basicStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="prepare"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="multiselect"/>
                <interceptor-ref name="actionMappingParams"/>
                <interceptor-ref name="params">
                    <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</param>
                </interceptor-ref>
                <interceptor-ref name="conversionError"/>
            </interceptor-stack>

            <!-- Sample validation and workflow stack -->
            <interceptor-stack name="validationWorkflowStack">
                <interceptor-ref name="basicStack"/>
                <interceptor-ref name="validation"/>
                <interceptor-ref name="workflow"/>
            </interceptor-stack>

            <!-- Sample file upload stack -->
            <interceptor-stack name="fileUploadStack">
                <interceptor-ref name="fileUpload"/>
                <interceptor-ref name="basicStack"/>
            </interceptor-stack>

            <!-- Sample model-driven stack  -->
            <interceptor-stack name="modelDrivenStack">
                <interceptor-ref name="modelDriven"/>
                <interceptor-ref name="basicStack"/>
            </interceptor-stack>

            <!-- Sample action chaining stack -->
            <interceptor-stack name="chainStack">
                <interceptor-ref name="chain"/>
                <interceptor-ref name="basicStack"/>
            </interceptor-stack>

            <!-- Sample i18n stack -->
            <interceptor-stack name="i18nStack">
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="basicStack"/>
            </interceptor-stack>

            <!-- An example of the paramsPrepareParams trick. This stack
                 is exactly the same as the defaultStack, except that it
                 includes one extra interceptor before the prepare interceptor:
                 the params interceptor.

                 This is useful for when you wish to apply parameters directly
                 to an object that you wish to load externally (such as a DAO
                 or database or service layer), but can't load that object
                 until at least the ID parameter has been loaded. By loading
                 the parameters twice, you can retrieve the object in the
                 prepare() method, allowing the second params interceptor to
                 apply the values on the object. -->
            <interceptor-stack name="paramsPrepareParamsStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="alias"/>
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="multiselect"/>
                <interceptor-ref name="params">
                    <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</param>
                </interceptor-ref>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="prepare"/>
                <interceptor-ref name="chain"/>
                <interceptor-ref name="modelDriven"/>
                <interceptor-ref name="fileUpload"/>
                <interceptor-ref name="staticParams"/>
                <interceptor-ref name="actionMappingParams"/>
                <interceptor-ref name="params">
                    <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</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>

            <!-- A complete stack with all the common interceptors in place.
                 Generally, this stack should be the one you use, though it
                 may do more than you need. Also, the ordering can be
                 switched around (ex: if you wish to have your servlet-related
                 objects applied before prepare() is called, you'd need to move
                 servletConfig interceptor up.

                 This stack also excludes from the normal validation and workflow
                 the method names input, back, and cancel. These typically are
                 associated with requests that should not be validated.
                 -->
            <interceptor-stack name="defaultStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="alias"/>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="prepare"/>
                <interceptor-ref name="chain"/>
                <interceptor-ref name="scopedModelDriven"/>
                <interceptor-ref name="modelDriven"/>
                <interceptor-ref name="fileUpload"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="multiselect"/>
                <interceptor-ref name="staticParams"/>
                <interceptor-ref name="actionMappingParams"/>
                <interceptor-ref name="params">
                    <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</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-ref name="debugging"/>
            </interceptor-stack>

            <!-- The completeStack is here for backwards compatibility for
                 applications that still refer to the defaultStack by the
                 old name -->
            <interceptor-stack name="completeStack">
                <interceptor-ref name="defaultStack"/>
            </interceptor-stack>

            <!-- Sample execute and wait stack.
                 Note: execAndWait should always be the *last* interceptor. -->
            <interceptor-stack name="executeAndWaitStack">
                <interceptor-ref name="execAndWait">
                    <param name="excludeMethods">input,back,cancel</param>
                </interceptor-ref>
                <interceptor-ref name="defaultStack"/>
                <interceptor-ref name="execAndWait">
                    <param name="excludeMethods">input,back,cancel</param>
                </interceptor-ref>
            </interceptor-stack>

       </interceptors>

        <default-interceptor-ref name="defaultStack"/>

        <default-class-ref class="com.opensymphony.xwork2.ActionSupport" />
    </package>
View Code

4. 使用拦截器

  • 将拦截器和拦截器栈定义好以后,就可以使用这些已定义的拦截器或拦截器栈来拦截Action了,拦截器或拦截器栈会先拦截并处理用户请求,然后再执行Action的execute方法。
  • 使用拦截器时需要在Action中进行配置,通过<interceptor-ref>标签来指定在Action中使用的拦截器。
 
默认拦截器的配置参考上节,本节讲述通过<interceptor-ref>标签来指定在Action中使用的拦截器。
<package name="default" extends="struts-default">
    <interceptors>
        <!--定义三个拦截器-->
        <interceptor name="interceptor1" class="interceptorClass"/>
        <interceptor name="interceptor2" class="interceptorClass"/>
        <interceptor name="interceptor3" class="interceptorClass">
            <param name="paramName">paranValue1</param>
        </interceptor>
        <!--定义一个拦截器栈-->
        <interceptor-stack name="myStack">
            <interceptor-ref name="interceptor1"/>
            <interceptor-ref name="interceptor2"/>
            <interceptor-ref name="defaultStack"/>
        </interceptor-stack>
    </interceptors>
    <action name="login" class="tutorial.Login">
        <result name="input">login.jsp</result>
        <!--在名为login的Action中使用已经定义的拦截器-->
        <interceptor-ref name="interceptor1"/>
        <interceptor-ref name="interceptor2"/>
        <interceptor-ref name="interceptor3">
            <param name="paramName">paramValue2</param>
        </interceptor-ref>
        <interceptor-ref name="myStack"/>
    </action>
</package>

注意:拦截器的参数指定有两种方式,一种是在定义拦截器时指定参数,该种方式指定的参数是默认参数;另一种是在使用拦截器时指定参数,该种方式指定的参数将会覆盖默认参数值。

上述内容摘录自:《Java Web整合开发实战》第8章

 

实例,未登录用户不予查看明细

1. JSP页面

login.jsp,登录界面

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ page isELIgnored="false"%>
<%@ taglib uri="/struts-tags" prefix="s"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <body>
        <font style="color:red"><s:property value="errorMessage"/></font>
        <s:form action="intercepLogin" method="post">
            账号:<s:textfield name="username"></s:textfield>
            <br />
            密码:<s:textfield name="password"></s:textfield>
            <br />
            <s:submit value="提交"></s:submit>
        </s:form>
    </body>
</html>

showDetail.jsp,显示详细信息页面

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ page isELIgnored="false"%>
<%@ taglib uri="/struts-tags" prefix="s"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <body>
        Hello, we are here!
    </body>
</html>

2. Action类与Interceptor类

InptercepLoginAction.java,处理登录请求

package com.clzhang.struts2.demo11;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

public class InptercepLoginAction extends ActionSupport {
    private String username;
    private String password;
    
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }

    public String execute() {
        System.out.println(username + "\t" + password);

        // 一到登录页面,即移除session中变量
        ActionContext.getContext().getSession().remove("userInfo");
        
        // 只要用户名与密码长度大于等于4,都认为是合法用户
        if (username.trim().length() >= 4 && password.trim().length() >= 4) {
            ActionContext.getContext().getSession().put("userInfo", username);
            
            return SUCCESS;
        }
        
        return INPUT;
    }
}

ShowAction.java,处理显示详细信息请求

package com.clzhang.struts2.demo11;

import com.opensymphony.xwork2.ActionSupport;

public class ShowAction extends ActionSupport {
    public String execute() {
        return SUCCESS;
    }
}

LoginInterceptor.java,拦截器类,处理检查用户是否已经登录

package com.clzhang.struts2.demo11;

import java.util.Map;

import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

public class LoginInterceptor extends AbstractInterceptor {

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        // 取得请求相关的ActionContext实例
        ActionContext ctx = invocation.getInvocationContext();
        Map session = ctx.getSession();
        String user = (String)session.get("userInfo");

        // 如果没有登陆
        if (user != null) {
            System.out.println("当前用户已经登录,继续处理请求...");
            
            return invocation.invoke();
        }

        ctx.put("errorMessage", "你还没有登录,或者登录超时,请重新登录后继续操作!");
        
        return Action.LOGIN;
    }
}

3. struts.xml文件修改如下内容

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
    <package name="myStruts" extends="struts-default">
        <interceptors>
            <interceptor name="authority" class="com.clzhang.struts2.demo11.LoginInterceptor">
            </interceptor>
            <!-- 拦截器栈 -->
            <interceptor-stack name="myDefault">
                <interceptor-ref name="defaultStack" />
                <interceptor-ref name="authority"/>
            </interceptor-stack>
        </interceptors>

        <global-results>
            <result name="login">/struts2/demo11/login.jsp</result>  
        </global-results>

        <action name="intercepLogin" class="com.clzhang.struts2.demo11.InptercepLoginAction">
            <result name="input">/struts2/demo11/login.jsp</result>
            <result name="success" type="redirectAction">
                <param name="actionName">intercepShow</param>
            </result>
        </action>

        <action name="intercepShow" class="com.clzhang.struts2.demo11.ShowAction">
            <result>/struts2/demo11/showDetail.jsp</result>
            <interceptor-ref name="myDefault"/>  
        </action>
    </package>
</struts>

4. 测试

打开IE,输入地址:http://127.0.0.1:8080/st/struts2/intercepShow.action

结果如下:

任意输入4位长度用户名与密码,登录,即可以显示详细页面。

posted @ 2013-12-29 21:18  那些年的事儿  阅读(844)  评论(0编辑  收藏  举报