美文网首页
SpringBoot 三种拦截http请求方式Filter,in

SpringBoot 三种拦截http请求方式Filter,in

作者: kaixingdeshui | 来源:发表于2020-10-04 18:14 被阅读0次

    SpringBoot 三种拦截http请求方式Filter,interceptor和aop。

    这三种拦截方式的拦截顺序是:filter—>Interceptor-->ControllerAdvice-->@Aspect -->Controller;

    这三种方式的区别:
    1.过滤器Filter可以拿到原始的HTTP请求和响应的信息, 但是拿不到你真正处理请求方法的信息,也就是方法的信息。
    2.拦截器Interceptor可以拿到原始的HTTP请求和响应的信息,也可以拿到你真正处理请求方法的信息,但是拿不到传进参数的那个值。
    3.切片Aspect,既然Spring那么支持AOP,可以拿到原始的HTTP请求和响应的信息, 也可以拿到你真正处理请求方法的信息,也可以传进参数的那个值。

    第一种方式:Filter

    实现Filter接口

    /**
     * 自定义Filter
     * 对请求的header 过滤token
     *
     * 过滤器Filter可以拿到原始的HTTP请求和响应的信息,
     *     但是拿不到你真正处理请求方法的信息,也就是方法的信息
     *
     * @Component 注解让拦截器注入Bean,从而让拦截器生效
     * @WebFilter 配置拦截规则
     *
     * 拦截顺序:filter—>Interceptor-->ControllerAdvice-->@Aspect -->Controller
     *
     */
    @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 我拦截到了请求");
    //        log.info("TokenFilter doFilter",((HttpServletRequest)request).getHeader("token"));
    
            chain.doFilter(request,response);//到下一个链
    
        }
    
        @Override
        public void destroy() {
            log.info("TokenFilter destroy");
        }
    }
    
    第二种方式:拦截器 Interceptor

    实现 HandlerInterceptor 接口,然后配置进Spring。

    /**
     * 自定义拦截器
     * 自定义拦截器后,需要配置进Spring
     *
     * 拦截器Interceptor可以拿到原始的HTTP请求和响应的信息,
     *    也可以拿到你真正处理请求方法的信息,但是拿不到传进参数的那个值。
     *
     *拦截顺序:filter—>Interceptor-->ControllerAdvice-->@Aspect -->Controller
     */
    @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());
    
            //spring boot 2.0对静态资源也进行了拦截,当拦截器拦截到请求之后,
            // 但controller里并没有对应的请求时,该请求会被当成是对静态资源的请求。
            // 此时的handler就是 ResourceHttpRequestHandler,就会抛出上述错误。
            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());
            }
    
            //false则表示不执行postHandle方法,不执行下一步chain链,直接返回response
            return true;
        }
    
        /**
         * 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
         * 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
     * 也可以mapping,跨域设置
     */
    @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("/**")//指定该类拦截的url
            .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>
    
    /**
     * pom.xml 添加Aop支持
     *     <dependency>
     *             <groupId>org.springframework.boot</groupId>
     *             <artifactId>spring-boot-starter-aop</artifactId>
     *         </dependency>
     *
     * 切片Aspect,既然Spring那么支持AOP,可以拿到原始的HTTP请求和响应的信息,
     *      也可以拿到你真正处理请求方法的信息,也可以传进参数的那个值。
     *
     * 拦截顺序:filter—>Interceptor-->ControllerAdvice-->@Aspect -->Controller
     */
    @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();//代理方法的返回值
        }
    }
    

    相关文章

      网友评论

          本文标题:SpringBoot 三种拦截http请求方式Filter,in

          本文链接:https://www.haomeiwen.com/subject/albnuktx.html