Springboot 三種攔截Rest API的方法-過濾器、攔截器、切片


過濾器方式實現攔截(Filter)

通過繼承Servlet的Filter類來實現攔截:

@Component
public class TimeFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("time filter init");
    }
    /**
     * 處理服務的請求時間
     * @param request
     * @param response
     * @param chain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //System.out.println("time filter start");
        long start = System.currentTimeMillis();
        chain.doFilter(request,response);
        //System.out.println("time filter 耗時:" + (System.currentTimeMillis() - start));
        //System.out.println("time filter finish");

    }
    @Override
    public void destroy() {
        //System.out.println("time filter destroy");
    }
}

假如這個Filter是第三方jar提供的,怎么加入我們自己的工程呢?通過org.springframework.boot.web.servlet.FilterRegistrationBean來加入

@Configuration
public class WebConfig {
    
    @Bean
    public FilterRegistrationBean timeFilter() {
        
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        
        TimeFilter timeFilter = new TimeFilter();
        registrationBean.setFilter(timeFilter);
        
        List<String> urls = new ArrayList<>();
        urls.add("/*");
        registrationBean.setUrlPatterns(urls);
        
        return registrationBean;
        
    }

}

攔截器方式實現攔截(Interceptor)

此種方式可以獲取到攔截的類名稱、方法名稱,不能獲取到方法參數,原因是在dispatcherservlet源碼中,經過preHandle才對方法參數通過request里面開始處理拼接)

1.繼承HandlerInterceptor,preHandle在控制器方法調用之前執行,postHandle在控制器方法正常執行后執行,afterCompletion不管控制器方法執行成功與否,都會執行;攔截器優於過濾器的地方就是攔截器有handler這個參數可以了解到針對哪個具體的方法進行了攔截。

@Component
public class TimeInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle");
        //打印類名
        System.out.println(((HandlerMethod)handler).getBean().getClass().getName());
        //打印方法名
        System.out.println(((HandlerMethod)handler).getMethod().getName());
        request.setAttribute("startTime",System.currentTimeMillis());
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object o, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle");
        Long start = (Long)request.getAttribute("startTime");
        System.out.println("time intercept 耗時:" + (System.currentTimeMillis() - start));
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object o, Exception ex) throws Exception {
        System.out.println("afterCompletion");
        Long start = (Long)request.getAttribute("startTime");
        System.out.println("time intercept 耗時:" + (System.currentTimeMillis() - start));
        System.out.println("ex is" + ex);
    }
}

2. 配置攔截器注入到spring容器(配置類需要繼承WebMvcConfigurerAdapter,重寫addInterceptors,手動添加自定義攔截器來到達注入的目的),也可為異步請求加入攔截器

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
    @Autowired
    private TimeInterceptor timeInterceptor;

    /**
     * 針對異步的攔截器配置,攔截異步請求
     * @param configurer
     */
    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
        super.configureAsyncSupport(configurer);
        //比如如下給異步服務請求添加攔截器
        //configurer.registerCallableInterceptors((CallableProcessingInterceptor) timeInterceptor);
    }
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(timeInterceptor);
    }
}

切片方式實現攔截(Aspect)

可以攔截到類名、方法名,方法參數名

@Aspect
@Component
public class TimeAspect {
    //切入點
    @Around("execution(* com.zlt.web.controller.UserController.*(..))")
    //增強
    public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable {

            System.out.print("time aspect start");
            Object[] args = pjp.getArgs();
            for (Object arg :args){
            System.out.println("arg is" + arg);
            }
            long start = System.currentTimeMillis();
            //調用被攔截的方法
            Object object = pjp.proceed();
            System.out.println("time filter 耗時:" + (System.currentTimeMillis() - start));
            System.out.println("time aspect end");
            return object; 
    }
}

小結

區別:

過濾器:可以拿到原始的HTTP請求和響應信息,拿不到處理請求的方法值信息 
攔截器:既可以拿到HTTP請求和響應信息,也可以拿到請求的方法信息,拿不到方法調用的參數值信息 
切片:可以拿到請求方法的傳入參數值,拿不到原始的HTTP請求和響應的對象

發起一個請求,若三者共存的情況下:

正常運行順序為:filter-interceptor-controllerAdvice-aspect-controller
異常情況下:controller-aspect-controllerAdvice-interceptor-filter

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM