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