SpringBoot 三种拦截 HTTP 请求方式:Filter,Interceptor 和 AOP。

# 对比

拦截顺序: Filter -> Interceptor -> ControllerAdvice -> @Aspect -> Controller

方法HTTP 请求、响应信息处理请求方法参数
过滤器 Filter××
拦截器 Interceptor×
切片 Aspect

# Filter

实现 Filter 接口

@Slf4j
@Component
@WebFilter(urlPatterns = {"/**"}, filterName = "tokenAuthorFilter") // 配置拦截规则
public class TokenFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("TokenFilter init {}", filterConfig.getFilterName());
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.info("TokenFilter doFilter 拦截到了请求");
        chain.doFilter(request, response);
    }
    @Override
    public void destroy() {
        log.info("TokenFilter destroy");
    }
}

# Interceptor

实现 HandlerInterceptor 接口

@Slf4j
@Component
public class TokenInterceptor implements HandlerInterceptor {
    /**
     * 访问 Controller 某个方法之前这个方法会被调用。
     *
     * @param request
     * @param response
     * @param handler
     * @return false 表示不执行 postHandle 方法,true 表示执行 postHandle 方法
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("Token Interceptor preHandle {}", "");
        String token = request.getHeader("token");
        log.info("Token Interceptor preHandle token :{}", token);
        log.info("Token Interceptor preHandle uri {}", request.getRequestURL().toString());
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            log.info("Token Interceptor preHandle getMethod {}", method.getName());
        } else if (handler instanceof ResourceHttpRequestHandler) {
            ResourceHttpRequestHandler resourceHttpRequestHandler = (ResourceHttpRequestHandler) handler;
            log.info("Token Interceptor preHandle getMethod {}", resourceHttpRequestHandler.getMediaTypes());
        }
        return true;
    }
    /**
     * 请求处理之后、视图渲染之前调用
     * preHandle 方法处理之后这个方法会被调用,如果控制器 Controller 出现异常,则不会执行此方法
     *
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("Token Interceptor postHandle");
    }
    /**
     * 不管是否出现异常,这个 afterCompletion 都会被调用
     *
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("Token Interceptor afterCompletion");
    }
}

配置 Spring 容器

/**
 * TokenInterceptor 自定义拦截器后,需要配置进 Spring
 * 可以 addCorsMappings 支持跨域
 */
@Slf4j
@Configuration
public class TokenConfig implements WebMvcConfigurer {
    @Autowired
    TokenInterceptor tokenInterceptor;
    /**
     * 添加拦截器
     *
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        log.info("TokenConfig addInterceptors tokenInterceptor");
        registry.addInterceptor(tokenInterceptor)
                .addPathPatterns("/**") // 加入拦截路径
                .excludePathPatterns("/static/**"); // 排除静态资源
    }
    /**
     * 如果实现 Filter 跨域拦截,这个跨域无效
     * 实现拦截器、支持跨域
     *
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        log.info("TokenConfig addInterceptors addCorsMappings");
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowCredentials(true)
                .allowedMethods("GET", "POST", "DELETE", "PUT", "OPTIONS", "HEAD")
                .allowedHeaders("*")
                .maxAge(3600);
    }
}

# AOP

pom.xml 添加 AOP 支持

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
@Slf4j
@Component // 表示它是一个 Spring 组件
@Aspect // 表示它是一个切面
public class HttpAspect {
    /**
     * 通过 ProceedingJoinPoint 对象的 getArgs () 方法获取传进来的参数
     * 通过 ProceedingJoinPoint 对象的 proceed () 方法获取返回值的对象
     *
     * @param pjp
     * @return
     * 环绕通知 包名。类名。方法名 (参数)
     */
    @Around("execution(* com.learn.jwttoken.controller.*.*(..))")
    public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable {
        log.info("HttpAspect handleControllerMethod filter start");
        // 原始 HTTP 请求、响应信息
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        HttpServletResponse response = attributes.getResponse();
        Signature signature = pjp.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        // 获取当前执行的方法
        Method targetMethod = methodSignature.getMethod();
        log.info("当前执行的方法:{}", targetMethod.getName());
        // 获取参数
        Object[] objs = pjp.getArgs();
        for (Object obj : objs) {
            log.info("参数:" + obj);
        }
        // 获取返回对象
        Object object = pjp.proceed();
        log.info("获取返回对象 :{}", object);
        log.info("HttpAspect handleControllerMethod filter end");
        // 代理方法的返回值
        return pjp.proceed();
    }
}