Spring 拦截器:你的请求休想逃过我的五指山!🚀🚀🚀

拦截器概述

在Spring框架中,拦截器(Interceptor)是一种强大的机制,它允许开发者在请求处理的不同阶段插入自定义逻辑。WebApplicationContext作为Spring Web应用的上下文容器,为拦截器的配置和管理提供了基础支持。

拦截器主要作用于以下场景:

权限验证

日志记录

性能监控

事务管理

通用行为注入等

拦截器与WebApplicationContext的关系

WebApplicationContext是Spring Web应用的IoC容器扩展,它继承自ApplicationContext,并添加了Web应用特有的功能。拦截器通过WebApplicationContext进行注册和管理,成为请求处理管道的一部分。

csharp 复制代码
public interface WebApplicationContext extends ApplicationContext {
    String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
    
    ServletContext getServletContext();
}

拦截器类型

HandlerInterceptor

最常用的拦截器接口,定义了三个关键方法:

java 复制代码
public interface HandlerInterceptor {
    default boolean preHandle(HttpServletRequest request, 
                             HttpServletResponse response, 
                             Object handler) throws Exception {
        return true;
    }
    
    default void postHandle(HttpServletRequest request, 
                          HttpServletResponse response, 
                          Object handler,
                          ModelAndView modelAndView) throws Exception {
    }
    
    default void afterCompletion(HttpServletRequest request, 
                               HttpServletResponse response, 
                               Object handler, 
                               Exception ex) throws Exception {
    }
}

AsyncHandlerInterceptor

HandlerInterceptor的扩展,增加了异步处理的支持。

WebRequestInterceptor

与HandlerInterceptor类似,但提供了更通用的WebRequest抽象,不依赖于Servlet API。

拦截器配置

XML配置方式

markdown 复制代码
    
    
    
    
    
        
        
    

Java配置方式

less 复制代码
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoggingInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/static/**");
        
        registry.addInterceptor(new AuthInterceptor())
                .addPathPatterns("/admin/**");
    }
}

注解方式

typescript 复制代码
@Component
public class MyInterceptor implements HandlerInterceptor {
    // 实现方法
}

@Configuration
public class InterceptorConfig {
    
    @Autowired
    private MyInterceptor myInterceptor;
    
    @Bean
    public WebMvcConfigurer adapter() {
        return new WebMvcConfigurer() {
            @Override
            public void addInterceptors(InterceptorRegistry registry) {
                registry.addInterceptor(myInterceptor);
            }
        };
    }
}

拦截器执行流程

拦截器在DispatcherServlet的处理流程中扮演重要角色:

  • preHandle:在处理器执行前调用

返回true继续执行

返回false中断请求处理

  • postHandle:在处理器执行后,视图渲染前调用

可修改ModelAndView

  • afterCompletion:在完整请求完成后调用

适合资源清理

高级拦截器特性

拦截器顺序控制

可以通过order属性控制多个拦截器的执行顺序:

scss 复制代码
registry.addInterceptor(new InterceptorA()).order(1);
registry.addInterceptor(new InterceptorB()).order(2);

路径匹配模式

支持Ant风格的路径模式:

  1. ? 匹配一个字符
    • 匹配零个或多个字符
  2. ** 匹配零个或多个目录

异步请求处理

对于异步请求,afterConcurrentHandlingStarted方法会被调用而不是postHandle和afterCompletion。

拦截器与过滤器的区别

特性 拦截器(Interceptor) 过滤器(Filter)
容器依赖 Spring容器 Servlet容器
作用范围 Spring MVC处理的请求 所有进入容器的请求
访问对象 可以访问Handler和方法信息 只能访问ServletRequest/Response
执行时机 在DispatcherServlet内部执行 在DispatcherServlet外部执行
依赖注入 支持 不支持

实际应用示例

日志拦截器

java 复制代码
public class LoggingInterceptor implements HandlerInterceptor {
    
    private static final Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class);
    
    @Override
    public boolean preHandle(HttpServletRequest request, 
                           HttpServletResponse response, 
                           Object handler) {
        long startTime = System.currentTimeMillis();
        request.setAttribute("startTime", startTime);
        logger.info("Request URL: {} : Start Time={}", 
                   request.getRequestURL(), startTime);
        return true;
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, 
                               HttpServletResponse response, 
                               Object handler, 
                               Exception ex) {
        long startTime = (Long) request.getAttribute("startTime");
        long endTime = System.currentTimeMillis();
        logger.info("Request URL: {} : End Time={} : Time Taken={}ms", 
                   request.getRequestURL(), endTime, (endTime - startTime));
    }
}

认证拦截器

java 复制代码
public class AuthInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request,
                            HttpServletResponse response,
                            Object handler) throws Exception {
        
        HttpSession session = request.getSession();
        if (session.getAttribute("user") == null) {
            response.sendRedirect("/login");
            return false;
        }
        return true;
    }
}

DEMO实测效果

被拦截

未被拦截

相关推荐
努力的小郑2 小时前
Canal 不难,难的是用好:从接入到治理
后端·mysql·性能优化
Victor3562 小时前
MongoDB(87)如何使用GridFS?
后端
Victor3562 小时前
MongoDB(88)如何进行数据迁移?
后端
小红的布丁3 小时前
单线程 Redis 的高性能之道
redis·后端
GetcharZp3 小时前
Go 语言只能写后端?这款 2D 游戏引擎刷新你的认知!
后端
宁瑶琴4 小时前
COBOL语言的云计算
开发语言·后端·golang
普通网友4 小时前
阿里云国际版服务器,真的是学生党的性价比之选吗?
后端·python·阿里云·flask·云计算
IT_陈寒5 小时前
Vue的这个响应式问题,坑了我整整两小时
前端·人工智能·后端
Soofjan6 小时前
Go 内存回收-GC 源码1-触发与阶段
后端
shining6 小时前
[Golang]Eino探索之旅-初窥门径
后端