欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring拦截器

程序员文章站 2022-07-09 18:46:54
...

拦截器的注册

    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/user/*"/>  
            <bean class="test.com.ch.springtest.TestIntercepter"></bean>
        </mvc:interceptor>
    </mvc:interceptors>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
    <mvc:interceptors>
            <bean class="test.com.ch.springtest.TestIntercepter1"></bean>
            <bean class="test.com.ch.springtest.TestIntercepter2"></bean>
    </mvc:interceptors>
  • 1
  • 2
  • 3
  • 4

拦截器的工作原理

1.spring mvc的拦截器 interceptor其实是web.xml里面servlet拦截器的下一级,比如

    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/user/index/*</url-pattern>
    </servlet-mapping>
  • 1
  • 2
  • 3
  • 4
  • 而自己创建的一个spring mvc拦截器想要拦截/user 这一层是不可能的
    <!-- 用到了mvc命名空间namespace 所以也要导入mvc的xmlns url -->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/user/*"/>    <!-- 规则:只拦截/user/index结尾的请求 -->
            <bean class="test.com.ch.springtest.TestIntercepter"></bean>
        </mvc:interceptor>
    </mvc:interceptors>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

结果:无意义的拦截器


正确的做法是web.xml的servlet拦截器拦截最上级的 ,例如:

    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>  //表明拦截http://localhost:8080/项目名称/  后面的
    </servlet-mapping>
  • 1
  • 2
  • 3
  • 4

而自己的拦截器则拦截更精准的,比如某个特定的功能,而后按需制定

    <!-- 用到了mvc命名空间namespace 所以也要导入mvc的xmlns url -->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/user/*"/>    <!-- 规则:只拦截/user/index结尾的请求 -->
            <bean class="test.com.ch.springtest.TestIntercepter"></bean>
        </mvc:interceptor>
    </mvc:interceptors>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

总结: 
请求先经过servlet过滤器,而后再经过你定义的拦截器,执行拦截器的preHandle方法,选择是否终止,而后到达具体逻辑代码块,执行完后得到的结果还会再经过拦截器的postHandle方法,这时候可以修改一些结果。


拦截器的具体实现

package test.com.ch.springtest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class TestIntercepter implements HandlerInterceptor{
    /**
     * afterCompletion在响应客户端后,调用的方法,一般较少用,主要用于销毁资源
     */
    @Override
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {
        // TODO Auto-generated method stub
        System.out.println("执行了方法afterCompletion");
    }

    /**
     * postHandle实在逻辑代码执行完之后,将要反馈给客户端的时候执行的,这时候可以修改一些数据
     * arg2代表controller对象,arg3代表返回的ModelAndView
     */
    @Override
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
            throws Exception {
        // TODO Auto-generated method stub
        System.out.println("执行了方法postHandle");

    }

    /**
     * preHandle会在进入实际的方法前执行,返回值决定是否继续执行下去,如果返回false,那么将被终止
     */
    @Override
    public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
        // TODO Auto-generated method stub
        System.out.println("执行了方法preHandle");
        return true;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

多个拦截器的工作顺序

  • 原理

Spring拦截器

Spring拦截器 
———————————————————————————————————————————— 
说明: 
-小明要回老家,开车需要经过两个收费站,收费站A,收费站B。 
-先经过收费站A(interceptorA-prehandler方法) 
-在经过收费站B(interceptorB-prehandler方法) 
-到老家过年,办完事了(具体的逻辑代码),需要返回自己的城市工作了 
-先经过收费站B(interceptorB-posthandler方法) 
-再经过收费站A(interceptorA-posthandler方法) 
-到了家了,过了段时间,收费站发来了发票 
-先收到了收费站B的发票(interceptorB-afterCompletion方法),因为B先收到钱,早一天开出发票 
-再收到了收费站A的发票(interceptorA-afterCompletion方法),因为A后收到钱,后一天开出发票


使用场景

  • 乱码问题(多余)
  • 解决权限验证问题(非常实用)
  • 过滤指定ip

    代码示例:

    /**
     * preHandle会在进入实际的方法前执行,返回值决定是否继续执行下去,如果返回false,那么将被终止
     */
    @Override
    public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
        /*
         * 使用场景1:编码
         */
        arg0.setCharacterEncoding("UTF-8");

        /*
         * 使用场景2:身份验证
         */
        System.out.println(arg0.getServerName());
        if (arg0.getSession().getAttribute("username") == null) {
            //如果用户没有登录,则终止请求,并且发送到登录页面
            arg0.getRequestDispatcher("/index.jsp").forward(arg0, arg1);
            return false;
        }
        return true;
    }

ps:一般含有session的网站用户信息都保存在session中,那么每次跳转的时候我们就可以在拦截器里面来判断是否是有效的用户,而无需在多个代码handler里面去判断用户是否合法
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

其他:

路径 @RequestMapping(value = “/index”) 不变,当

//第一种
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>  
    </servlet-mapping>
  • 1
  • 2
  • 3
  • 4
  • 5

则浏览器输入的是 
http://localhost:8080/SpringTest/user/index

//第二种
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>*.do</url-pattern>  
    </servlet-mapping>
  • 1
  • 2
  • 3
  • 4
  • 5

则浏览器输入的是 
http://localhost:8080/SpringTest/user/index.do