这里了解一下restful api的拦截,文本主要介绍三种方式来对api进行拦截,参考本文可实现拦截api,进行一些附加操作,比如打印拦截到的方法所在类名,获取原始的request,拦截到api的调用的方法名,还可以根据需要实现打印出方法的参数。当然,下面介绍的拦截器、过滤器、切片功能不全一样,侧重点不同。希望可以给大家带来帮助。
1、自定义过滤器:
/**
* @author: zhoulitong
* @date: 2018/4/23
* @description:
*/
@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");
}
}
2、配置过滤器注入到spring容器:
/**
* @author: zhoulitong
* @date: 2018/4/23
* @description:
*/
@Configuration
public class WebConfig{
@Bean
public FilterRegistrationBean timeFilter(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
TimeFilter timeFilter = new TimeFilter();
registrationBean.setFilter(timeFilter);
List urls = new ArrayList<>();
//此过滤器在以下url中会起作用
urls.add("/*");
registrationBean.setUrlPatterns(urls);
return registrationBean;
}
}
3、特点:此种方式配置可以实现自定义过滤URL的操作,不可从request中拿到
1、自定义拦截器:
/**
* @author: zhoulitong
* @date: 2018/4/23
* @description: 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,手动添加自定义拦截器来到达注入的目的),也可为异步请求加入拦截器
/**
* @author: zhoulitong
* @date: 2018/4/23
* @description: 配置TimeInterceptor需要extends WebMvcConfigurerAdapter
*/
@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);
}
}
3、特点:此种方式可以获取到拦截的类名称、方法名称,不能获取到方法参数,原因是在dispatcherservlet源码中,经过preHandle才对方法参数通过request里面开始处理拼接)
1、自定义切片:
@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;
}
}
2、特点:可以拦截到类名、方法名,方法参数名
过滤器:可以拿到原始的HTTP请求和响应信息,拿不到处理请求的方法值信息
拦截器:既可以拿到HTTP请求和响应信息,也可以拿到请求的方法信息,拿不到方法调用的参数值信息
切片:可以拿到请求方法的传入参数值,拿不到原始的HTTP请求和响应的对象
正常运行顺序为:filter-interceptor-aspect
异常情况下:aspect-interceptor-filter