struts拦截器

拦截器杂谈

截拦器,在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,停止拦截然后在之前或以后加入某些操作。拦截器是AOP的一种实现策略。
拦截器是动态拦截Action调用的对象。它供给了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也是供给了一种可以提取action中可重用的部分代码的方式。
Struts2很多核心的功能都是拦截器来实现!如:从请求中把请求参数封装到action、文件上传和数据验证等等都是通过拦截器实现的。

拦截器栈(Interceptor Stack)相似于过滤器链。拦截器栈就是将拦截器按必定的顺序联结成一条链。在拜访被拦截的方法或字段时,拦截器栈的拦截器就会按其之前定义的顺序被调用。

也可以叫做拦截器链(Interceptor Stack),拦截器栈一词更确明的表名了拦截器链的实现式方。

拦截器的工作流程

如下图所示:
这里写图片描述
工作流程大致如下:
1.启动Tomcat服务器,加载web.xml,初始化过滤器(StrutsPrepareAndExecuteFilter)
2.创建拦截器实例(构造器),初始化每个拦截器init()。
3.当用户请求访问,Struts找到指定哪个action,创建Action实例
4.执行第一个拦截器的interceptor()方法,执行一些业务操作之后,调用invoke()方法
5.如果有下一个拦截器,继续执行interceptor(),直到没有,执行action的execute()方法,处理请求,并返回return 值。
6.返回值依次经过拦截器,最终将响应发送给浏览器。

一个小面试题

先执行action类创建,还是先执行拦截器?
答:先执行Action类的创建,再执行拦截器; 然后拦截器inteceptor()业务处理执行完,再执行action中的业务方法。

自定义拦截器

因为struts2中如文件上传,数据验证,封装请求参数到action等功能都是由系统默认的defaultStack中的拦截器实现的,所以我们定义的拦截器需要引用系统默认的defaultStack,这样应用才可以使用struts2框架提供的众多功能。
如果希望包下的所有action都使用自定义的拦截器,可以通过<default-interceptor-ref name=“permissionStack”/>把拦截器定义为默认拦截器。注意:每个包只能指定一个默认拦截器。另外,一旦我们为该包中的某个action显式指定了某个拦截器,则默认拦截器不会起作用。

自定义拦截器代码

注意:——–配置中
自定义的拦截器的引用一定要在默认拦截器的下面!

com.opensymphony.xwork2.interceptor.Interceptor
阅读该接口API,所有的自定义拦截器都需要实现该接口,且以单例运行。
HelloInterceptor.java


/**
 * 自定义拦截器
 *
 */
public class HelloInterceptor implements Interceptor{

    // 服务器启动时候执行
    public HelloInterceptor(){
        System.out.println("创建了拦截器实例");
    }

    // 启动时候执行
    @Override
    public void init() {
        System.out.println("执行了拦截器的初始化方法");
    }

    // 拦截器业务处理方法 (在访问action时候执行? 在execute之前执行?)
    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        System.out.println("2. 拦截器,业务处理-开始");

        // 调用下一个拦截器或执行Action  (相当于chain.doFilter(..)
        // 获取的是: execute方法的返回值
        String resultFlag = invocation.invoke();

        System.out.println("4. 拦截器,业务处理-结束"+resultFlag);

        return resultFlag;
    }

    @Override
    public void destroy() {
        System.out.println("销毁....");
    }

}

struts.xml


/**
 * 自定义拦截器
 *
 */
public class HelloInterceptor implements Interceptor{

    // 服务器启动时候执行
    public HelloInterceptor(){
        System.out.println("创建了拦截器实例");
    }

    // 启动时候执行
    @Override
    public void init() {
        System.out.println("执行了拦截器的初始化方法");
    }

    // 拦截器业务处理方法 (在访问action时候执行? 在execute之前执行?)
    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        System.out.println("2. 拦截器,业务处理-开始");

        // 调用下一个拦截器或执行Action  (相当于chain.doFilter(..)
        // 获取的是: execute方法的返回值
        String resultFlag = invocation.invoke();

        System.out.println("4. 拦截器,业务处理-结束"+resultFlag);

        return resultFlag;
    }

    @Override
    public void destroy() {
        System.out.println("销毁....");
    }

}

在启动服务器之后,控制台将会打印:
创建了拦截器实例
执行了拦截器的初始化方法
在用户请求访问HelloAction时,会打印
2. 拦截器,业务处理-开始
如果有多个拦截器,将会执行多个拦截器业务方法,然后会执行action中的业务方法。最后action返回标记如:

String resultFlag = invocation.invoke();

最后打印:4. 拦截器,业务处理-结束。
当服务器关闭时,打印 销毁….

注意—–ActionInvocation: 代表一个给定Action的执行状态, 拦截器可以从该类的对象里获得与该Action相关联的 Action 对象和 Result 对象. 在完成拦截器自己的任务之后, 拦截器将调用 ActionInvocation 对象的 invoke 方法前进到 Action 处理流程的下一个环节.

拦截器案例–简单登录拦截器

功能描述:当用户访问login.jsp登录页面时,拦截器直接放行,当用户访问list.jsp列表页面时,拦截器执行拦截,需要判断该用户是否已经登录,如果登录,直接放行,如果没有登录,则跳转到login.jsp登录页面。其中用户登录之后将用户信息保存到session中。

代码如下:
login.jsp

<body>
     <form method="post" action="${pageContext.request.contextPath }/user_login.action">
        用户名:<input type="text" name="admin.userName"><br/>
        密码:<input type="text" name="admin.pwd"><br/>
        <input type="submit" value="登陆"><br/>
     </form>
  </body>

UserAction.java


public class UserAction extends ActionSupport {

    // ---------1. 自动封装请求数据-----------
    private Admin admin;
    public Admin getAdmin() {
        return admin;
    }
    public void setAdmin(Admin admin) {
        this.admin = admin;
    }
    // ---------2. 调用的Service(没用注入)-----------
    private AdminService adminService = new AdminService();

    // 用户登陆
    public String login() {
        try {
            Admin userInfo = adminService.login(admin);
            // 判断是否有该用户
            if (userInfo == null){
                // 登陆失败
                return "input";
            }
            // 登陆成功:将用户保存在session中
            ActionContext.getContext().getSession().put("userInfo", userInfo);

            // 登陆成功
            return "loginSuccess";
        } catch (Exception e) {
            return ERROR;
        }
    }

    // 列表显示所有的用户数据
    public String list() {
        try {
            // 查询全部
            List<Admin> list = adminService.getAll();
            // 保存到request
            ActionContext.getContext().getContextMap().put("listAdmin", list);
            return "list";
        } catch (Exception e) {
            return ERROR;
        }
    }

    public String add() {
        return null;
    }

}

list.jsp

<body>
    <h1>欢迎你,${userInfo.userName }</h1>
    <table align="center" border="1">
        <tr>
            <td>序号</td>
            <td>编号</td>
            <td>用户名</td>
            <td>密码</td>
        </tr>
        <%--@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" --%>
        <!-- 用struts标签迭代数据 -->
        <%@taglib uri="/struts-tags" prefix="s" %>
        <s:iterator var="admin" value="#request.listAdmin" status="st">
            <tr>
                <td>
                    <s:property value="#st.count"/>
                </td>
                <td>
                    <s:property value="#admin.id"/>
                </td>
                <td>
                    <s:property value="#admin.userName"/>
                </td>
                <td>
                    <s:property value="#admin.pwd"/>
                </td>
            </tr>
        </s:iterator>

    </table>
  </body>

自定义拦截器UserCheckInterceptor.java


public class UserCheckInterceptor extends AbstractInterceptor{

    /**
     * 拦截器业务处理方法
     */
    public String intercept(ActionInvocation invocation) throws Exception {
        // 拿到当前执行的方法名:判断,只有当前方法名不是login,就进行验证
        //不登录不能访问list.jsp页面
        // 获取ActionContext对象
        ActionContext ac = invocation.getInvocationContext();

        // 获取action的代理对象
         ActionProxy proxy = invocation.getProxy();
         // 获取当前执行的action中的方法名
         String methodName = proxy.getMethod();
         // 判断
         if (!"login".equals(methodName)) {
             // 先获取当前登陆的用户
             Object obj = ac.getSession().get("userInfo");
             if (obj == null) {
                 // 没有登陆
                 return "input";
             } else {
                 // 当前用户有登陆
                 return invocation.invoke();
             }
         } else {
             // 说明当前用户正在登陆
             return invocation.invoke();
         }
    }

}

配置拦截器 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="user" extends="struts-default">

        <!-- 【拦截器配置】 -->
        <interceptors>
            <interceptor name="loginCheck" class="UserCheckInterceptor"></interceptor>
            <interceptor-stack name="myStack">
                <interceptor-ref name="defaultStack"></interceptor-ref>
                <interceptor-ref name="loginCheck"></interceptor-ref>
            </interceptor-stack>
        </interceptors>
        <!-- 【执行拦截器:第一种写法: 当前包下所有的acntion都执行myStack栈】
        <default-interceptor-ref name="myStack"></default-interceptor-ref>
         -->

        <!-- 全局配置 -->
        <global-results>
            <result name="error">/error.jsp</result>
        </global-results>

        <action name="user_*" class="UserAction" method="{1}">

            <!--第二种写法: 只是在这一个Action中执行myStack栈 
            <interceptor-ref name="defaultStackt"></interceptor-ref>
            <interceptor-ref name="loginCheck"></interceptor-ref>
            -->

            <!-- 第三种写法:执行用户栈(与第二种写法一样, 只在当前aciton中执行自定义栈) -->
            <interceptor-ref name="myStack"></interceptor-ref>

            <!-- 1. 登陆失败 -->
            <result name="input">/login.jsp</result>

            <!-- 2. 登陆成功 -->
            <result name="loginSuccess" type="redirectAction">user_list</result>

            <!-- 3. 列表展示 -->
            <result name="list">/WEB-INF/list.jsp</result>

        </action>

    </package>
</struts>

小面试题之二

过滤器和struts2拦截器的区别?
答:
都是对于用户的请求起到拦截的作用,只不过Filter是Java EE规范的概念,而拦截器Interceptors
是Struts2中提出的概念! Struts2中过滤器负责调用拦截器!

拦截器与过滤器的区别 : 

1、拦截器是基于java的反射机制的,而过滤器是基于函数回调 

2、过滤器依赖与servlet容器,而拦截器不依赖与servlet容器 

3、拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用 

4、拦截器可以访问action上下文、值栈里的对象,而过滤器不能 

5、在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值