SpringBoot(八)拦截器Interceptor

上篇介绍了Filter过滤器的使用,提起过滤器,就不得不再提起另外一个叫做拦截器的东西。两者的作用类似,都可以实现拦截请求的作用,但其实两者有着非常大的区别。本篇,我们就来学习下拦截器的使用。

如果你是新手,且没看过我之前的一系列SpringBoot文章,建议至少看一下这一篇:

SpringBoot(四)SpringBoot搭建简单服务端_springboot做成服务_heart荼毒的博客-CSDN博客​​​​​​​

如果你想从头到尾系统地学习,欢迎关注我的SpringBoot专栏,持续更新:

https://blog.csdn.net/qq_21154101/category_12359403.html

一、拦截器Interceptor​​​​​​​

拦截器跟过滤器有着非常相似的作用,过滤器可以做到的事情,拦截器也可以做到,甚至可以做到更好。

Filter是Servlet的一个概念或者组件,而Interceptor是Spring的一个概念或组件。大家都知道,做web开发,最原始的时候不是用Spring或者SpringBoot,而是Jsp + servlet(我至今还记得大三的时候在机房上机,在那配置tomcat,配置Servlet....)。Spring以及后续的SpringBoot都是为了简化开发,在这里我们暂且不去详细的比较二者。

同样的,拦截器是位于客户端可服务端中间的组件,可以有0-多个,跟过滤器类似:

二、自定义拦截器

SpringBoot提供了对拦截器的支持,使用也非常方便。首先,实现HandlerInterceptor接口,创建一个拦截器。在这里,仅模拟拦截器的实现,写了个非常简单的逻辑,如果请求串包含"sb"就拦截,否则放行:

java 复制代码
package com.zhaojun.server.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("拦截器处理中...");
        String queryString = request.getQueryString();
        if (queryString.contains("sb")) {
            System.out.println("拦截");
            return false;
        }
        System.out.println("放行");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("拦截器处理结束...");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("请求结束...");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

接下来,需要去配置一下拦截器,创建一个Config类,实现WebMvcConfigurer接口,并且添加@Configuration注解:

java 复制代码
package com.zhaojun.server.interceptor;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/login");
    }
}

三、验证拦截器是否生效

接下来,测试下拦截器是否生效。首先,使用不包含sb的url进行请求http://localhost:8080/login?name=zj&phone=156532890870&password=123456

看代码执行的流程:

可以看到,首先走到了preHandle,因为不包含特定字符sb,放行。然后依次走到了postHandle和afterCompletion。并且,因为我是接着上一篇的filter继续写的,细心的朋友可以看到,过滤器是在拦截器之前执行的。

接下来,使用包含特地字符sb的url进行请求。http://localhost:8080/login?name=sb&phone=156532890870&password=123456

可以看到,因为包含特定的字符sb,成功在preHandle进行了拦截。这样,因为拦截成功了,自然也不会执行后续的postHandlle和afterCompletion。

四、多个拦截器

学习过滤器的时候,我们可以设置多个过滤器。拦截器前面也提到过了,可以有0-多个。接下来,我们再创建一个拦截器,代码直接复制第一个的,只看下执行的流程:

java 复制代码
package com.zhaojun.server.interceptor;

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

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

public class Interceptor2 implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("拦截器2处理中...");
        String queryString = request.getQueryString();
        if (queryString.contains("sb")) {
            System.out.println("拦截");
            return false;
        }
        System.out.println("放行");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("拦截器2处理结束...");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("请求结束2...");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

相应的,需要在Config类中添加这个拦截器:

java 复制代码
package com.zhaojun.server.interceptor;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/login");
        registry.addInterceptor(new Interceptor2());
    }
}

分别用不含有sb的url 和含有sb的url请求,执行流程如下:

可以看到一些规则,在这里也简单的总结下:

(1)当第一个拦截器没有在preHandle进行拦截的情况下,会顺序执行到第二个拦截器的preHandle。

(2)如果第二个拦截器也没有在preHandle拦截,那么接下来依次倒序执行postHandle和afterCompletion。

(3)如果第一个拦截器没有拦截,第二个拦截器拦截了,那么会直接执行第一个拦截器的afterCompletion。

(4)如果第一个拦截器拦截了,那么后续的拦截器也不会再执行。

相关推荐
yxlalm5 小时前
Spring AI+RAG 01-项目背景与技术选型
java·人工智能·spring
程序员清风6 小时前
Java 后端高并发设计:线程池、限流、熔断与降级
java·数据库·oracle
码事漫谈6 小时前
多人共用一个 key,缓存命中率会不会因此降低?
后端
Seoyoneh6 小时前
Agentic Workflow编排架构:云客服从“被动响应”迈向“主动执行”的技术实现
java·开发语言·架构
海南java第二人6 小时前
对外 API 如何保证幂等性?插入数据 / 上传表格场景全方案汇总
java·幂等性
tryxr7 小时前
Chat2Excel 文件服务模块上传文件功能开发
java·项目·oss·easyexcel·文件服务
Tangyuewei7 小时前
Java 写 Agent:模型只是组件
java·开发语言
考虑考虑7 小时前
docker compose环境变量替换
运维·后端·自动化运维
彧azz8 小时前
Java学习语法篇:变量
java·学习
武雄(小星Ai)8 小时前
飞书API上传26MB文件偶发失败:错误码9499与空响应体排坑实录
后端·api·排坑实录