過濾器方式實現攔截(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