SpringBoot拦截器的使用

分类:
JAVA
标签:
SpringBoot
拦截器
作者:
何鑫
创作时间:
2019/08/03 22:57:45

摘要:SpringBoot拦截器的运用介绍

学习SpringBoot(本文基于2.x版本),拦截器的使用是必须要掌握的。在实际工作过程中,我们经常会使用到SpringBoot的拦截器,通常我们可以通过拦截器实现权限控制,日志监控等操作,有了拦截器,我们就不用在每个请求方法前后反复去写这些重复的实现代码,从而可以使代码更加简洁,易于维护。

SpringBoot拦截器实现第一步:继承HandlerInterceptorAdapter

基础demo的搭建在这里不再赘述,推荐使用IDEA快速生成SpringBoot基础代码。

我们在新建一个interceptor包用于存放拦截器,并新建一个类继承HandlerInterceptorAdapter:

public class LabInterceptor extends HandlerInterceptorAdapter {

}

我们来看一下此类中的方法:

除去继承自Object方法以及该类构造方法,共有4个方法需要我们留意,分别是preHandle,postHandle,afterCompletion,afterConcurrentHandingStart

ed。

  • preHandle:见名知意,在请求方法执行前调用,返回一个布尔值,如果为true,则继续往下执行,为false则停止执行,常用于权限校验。

  • postHandle:在请求方法主体结束后,返回值返回前执行,如果在方法执行过程中抛出异常,则不会被执行。

  • afterCompletion:在请求方法执行完成后执行,不管方法执行成功还是失败都会执行,在此方法中可以拿到异常。

  • afterConcurrentHandingStarted:使用非常少,用于处理异步请求,这里先不做研究,有兴趣的同学请自行查询相关文档。

我们在LabInterceptor中重写前三个方法:

public class LabInterceptor extends HandlerInterceptorAdapter {

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

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("执行postHandle...");
        super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("执行afterCompletion...");
        super.afterCompletion(request, response, handler, ex);
    }

}

先简单的输出几句话即可,然后我们就可以进行到第二步。

SpringBoot拦截器实现第二步:配置拦截器

新建一个config包,在此包下新建一个类WebConfig,实现WebMvcConfigurer,实现这个接口可以进行一些web配置,包括拦截器,资源映射,JSON转换等配置。

在WebConfig类上加上@Configuration注解,注入我们前面写的拦截器,重写addInterceptors方法添加对应拦截器:

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Bean
    public LabInterceptor labInterceptor() {
        return new LabInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(labInterceptor()).addPathPatterns("/hello");
    }

}

addPathPatterns是指我们需要拦截的请求路径,接收参数是一个String类型的可变参数或者List集合,可添加多个路径,我们这里只拦截了/hello请求,除此之外我们还可以使用excludePathPatterns告诉拦截器不要拦截一些请求,它的参数与addPathPatterns的参数是一致的,可以接收一个String类型的可变参数或List集合。

添加完成后我们在新建一个controller包,增加一个controller,添加一个请求方法,请求路径为/hello:

@RestController
public class LabController {

    @GetMapping("/hello")
    public String test() {
        return "hello";
    }

}

启动SpringBoot,我们来看一下拦截器的执行情况,请求http://localhost:8080/hello,页面输出hello,请求成功,控制台输出:

我们可以清楚的看到拦截器的执行顺序。

我们改变一下,在原代码中抛出一个异常看下会发生什么:

@RestController
public class LabController {

    @GetMapping("/hello")
    public String test() {
        System.out.println(1/0);
        return "hello";
    }

}

可以知道的,这里会抛出除0异常,我们重新启动程序并重新请求:

可以看到,postHandle并未执行,因为我们在返回前就已经抛出了异常。我们也可以在afterCompletion捕获到该异常,我们可以看到在afterCompletion中有一个Exception类型的参数,利用它我们就可以获取异常了,限于篇幅,这里就不做演示了,大家可自行测试。

多个拦截器的执行顺序

前面我们只讲解了一个拦截器,那么如果我们配置多个拦截器,它的执行顺序会是怎样的呢,我们再添加一个拦截器测试一下:

拦截器2号:

public class LabTwoInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("拦截器2-执行preHandle...");
        return super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("拦截器2-执行postHandle...");
        super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("拦截器2-执行afterCompletion...");
        super.afterCompletion(request, response, handler, ex);
    }
}

配置该拦截器:

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Bean
    public LabInterceptor labInterceptor() {
        return new LabInterceptor();
    }

    @Bean
    public LabTwoInterceptor labTwoInterceptor() {
        return new LabTwoInterceptor();
    }


    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(labInterceptor()).addPathPatterns("/hello");
        registry.addInterceptor(labTwoInterceptor()).addPathPatterns("/hello");
    }

}

启动程序,执行请求:

可以看到尽管拦截器二号在拦截器一号后添加,但是除preHandle是顺序调用之外,其他两个都是逆序调用。

preHandle返回false

前面说过,如果preHandle如果返回false,是不会向下执行的,我们来验证一下。

在LabInterceptor中:

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    System.out.println("执行preHandle...");
    return false;
    // return super.preHandle(request, response, handler);
}

重新请求后只输出了一个,所以我们可以知道如果preHandle返回false,不只是这个拦截器不会向下执行,其他后面添加的拦截器都不会执行!

至此,本文已经介绍完了基本的拦截器实现,但是我们还没有研究拦截器各个方法中参数含义及其运用,我会在后续更新相关文章,欢迎关注,谢谢!


发表评论

温馨提示: 评论先审核后发布, 请勿发表不良言论

所有评论