SpringMVC 拦截器

目录

一、拦截器Interceptor介绍

二、拦截器定义的步骤-MVC方式

三、拦截器的细节

四、拦截器链的实现-基于SpringBoot

1、定义拦截器

2、配置拦截器


一、拦截器Interceptor介绍

拦截是AOP的一种实现策略。在Webwork的中文文档的解释为:拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也是提供了一种可以提取action中可重用的部分的方式。

拦截器和过滤器的区别:

过滤器 和 拦截器 均体现了AOP的编程思想(都用到了反射),都可以实现诸如日志记录、登录鉴权等功能,但二者也存在区别:

Filter拦截的目标是servlet的执行而拦截器拦截的是Spring MVC定义的概念,叫Handler(常见的就是我们用RequestMapping定义出来的HandlerMethod)。觉得它相似是因为Spring的Handler就是DispatcherServlet使用的,而后者就是一Servlet。Filter包围着DispatcherServlet,而它自己也想去执行一个目标Handler,并在执行周围包裹着拦截器,好处是拦截器可以被容器管理,从而获得被容器赋予的能力,而Filter不行(这样一想和代理Filter使用ApplicationFilterChain很类似,只是拦截器更贴近执行业务的方法)。没有什么其它更本质上的区别。

Spring 拦截器和过滤器的区别? - 知乎

拦截器链(Interceptor Chain,拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。

二、拦截器定义的步骤-MVC方式

第一步:编写一个普通类实现 HandlerInterceptor 接口

/**
 * @author swadian
 * @date 2021/2/8
 * @Version 1.0
 * @describetion
 */
public class HandlerInterceptorDemo implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        System.out.println("preHandle 拦截器拦截了");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle 方法执行了");
    }
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        System.out.println("afterCompletion 方法执行了");
    }
}

第二步:在springmvc.xml中配置拦截器

<!-- 配置拦截器 -->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean id="handlerInterceptorDemo" class="com.test.controller.HandlerInterceptorDemo"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

编写测试方法 

    /**
     * 拦截器测试方法
     */
    @RequestMapping("/testHandle")
    public String testRedirect() {
        System.out.println("AccountController 的 testHandle 方法执行 了。。。。");
        return "success";
    }

测试结果,拦截器在方法前后实现拦截

三、拦截器的细节

拦截器的放行

放行的含义是指,如果有下一个拦截器就执行下一个,如果该拦截器处于拦截器链的最后一个,则执行控制器中的方法。

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        System.out.println("preHandle 拦截器拦截了");
        return true; // 为true时进行放行,为false时进行拦截,后边程序不再执行
    }

拦截器执行流程图示

拦截器接口

// 拦截器接口
public interface HandlerInterceptor {
    /** 
     * 在控制器的处理请求方法前调用
     */
    boolean preHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
    /** 
     * 在控制器的处理请求方法调用之后,解析视图之前执行  
     */
    void postHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3, ModelAndView var4) throws Exception;
    /** 
     * 在控制器的处理请求方法执行完成后执行,即视图渲染结束之后执行 
     */
    void afterCompletion(HttpServletRequest var1, HttpServletResponse var2, Object var3, Exception var4) throws Exception;
}

拦截器的作用路径

作用路径可以通过在配置文件中配置。

    <!-- 配置拦截器 -->
    <mvc:interceptors>
        <mvc:interceptor>
            <!-- 用于指定拦截的 url -->
            <mvc:mapping path="/**"/>
            <!-- 用于指定排除的 url-->
            <mvc:exclude-mapping path="/login/**"/>
            <bean id="handlerInterceptorDemo" class="com.test.controller.HandlerInterceptorDemo"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

多个拦截器的执行顺序

多个拦截器是按照配置的顺序决定的

四、拦截器链的实现-基于SpringBoot

1、定义拦截器

首先定义两个拦截器LoginInterceptor.java,VisitInterceptor.java;实现HandlerInterceptor接口,代码如下:

拦截器一:LoginInterceptor.java用于验证用户的登录

import org.springframework.web.servlet.HandlerInterceptor;

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

/**
 * @author swadian
 * @date 2022/2/21
 * @Version 1.0
 * 拦截器
 */
public class LoginInterceptor implements HandlerInterceptor {
    @Override //进入Controller之前执行该方法
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Object object = request.getSession().getAttribute("userName");
        System.out.println("LoginInterceptor执行...");
        if (object == null) {
            throw new Exception("用户没有登录!");
        }
        return true;//为true时进行放行,为false时进行拦截,后边程序不再执行
    }
}

拦截器二:VisitInterceptor.java

import org.springframework.web.servlet.HandlerInterceptor;

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

/**
 * @author swadian
 * @date 2022/2/21
 * @Version 1.0
 * 拦截器
 */
public class VisitInterceptor implements HandlerInterceptor {

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("VisitInterceptor执行...");
        return true;
    }
}

2、配置拦截器

创建一个配置类InterceptorConfig,并实现WebMvcConfigurer接口, 覆盖接口中的addInterceptors方法,并为该配置类添加@Configuration注解,标注此类为一个配置类,让Spring Boot 扫描到,这里的操作就相当于SpringMVC的注册拦截器 ,@Configuration就相当于一个applicationContext-mvc.xml

import com.swadian.spring_learn.LoginInterceptor;
import com.swadian.spring_learn.VisitInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author swadian
 * @date 2022/2/21
 * @Version 1.0
 */
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    public void addInterceptors(InterceptorRegistry registry) {
        //需要拦截的路径,/**表示需要拦截所有请求
        String[] addPathPatterns = {"/**"};
        //不需要拦截的路径
        String[] excludePathPaterns = {
                "/login/submit",
                "/login/logout"
        };
        //注册一个登录拦截器
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns(addPathPatterns)
                .excludePathPatterns(excludePathPaterns);
        //注册一个权限拦截器  如果有多个拦截器,只需要添加以下一行代码
        registry.addInterceptor(new VisitInterceptor())
                .addPathPatterns(addPathPatterns)
                .excludePathPatterns(excludePathPaterns);
        /**
         * 拦截器的顺序根据你加入的顺序来的
         * VisitInterceptor,LoginInterceptor就是拦截器具体逻辑的内容的2个类,需要实现implements HandlerInterceptor
         * 拦截路径个过滤路径都是自己看业务定义
         */
    }
}

测试:接下来写一个Controller类可以用来测试程序。

import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

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

/**
 * @author swadian
 * @date 2022/2/21
 * @Version 1.0
 */
@RestController
@RequestMapping("/login")
public class LoginController {

    //登录
    @RequestMapping("/submit")
    public String login(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String userName = request.getParameter("userName");
        if (!StringUtils.isEmpty(userName)) {
            request.getSession().setAttribute("userName", userName);
            return "登录成功!";
        }
        return "登录失败";
    }

    //退出
    @RequestMapping("/logout")
    public String logout(HttpSession session) throws Exception {
        // session 过期
        session.invalidate();
        return "退出登录";
    }

    //退出
    @RequestMapping("/visit")
    public String visit(String visitParam) throws Exception {
        // session 过期
        return "访问成功:" + visitParam;
    }
}

访问/submit方法进行登录,如果没有登录,拦截器中的异常会抛出

然后访问/visit方法,成功登录

 拦截器执行顺序,LoginInterceptor先配置,先执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

swadian2008

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值