title: RESTful API的拦截
tags: [Spring,restful,filter,aspect,interceptor]
date: 2018/5/12 23:46:25
categories:
- 开发
- java
总的来说拦截请求,我们在开发过程中会遇到以下3种方式
- 自定义过滤器 Servlet Filter
- Spring Mvc Interceptor
- Aspect
自定义过滤器
特点和局限
-
可以拿到原始的http请求和响应的信息
-
但是拿不到真正处理请求的那个方法的信息,因为真正处理请求的方法信息不是由servlet提供的 ,一般是由mvc框架(如:spring mvc -> controller -> method() ) 提供的
关键代码
@Component
public class XXXFilter implements Filter{
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("doFilter start");
// 对request response 进行拦截处理
// 放行给其它过滤器->处理业务
chain.doFilter(request, response);
System.out.println("doFilter finish");
}
……
}
配置启用
-
xml(省略)
-
spring boot
@Configuration public class WebConfig { @Bean public FilterRegistrationBean xxxFiler() { FilterRegistrationBean registrationBean = new FilterRegistrationBean(); XXXFilter xxxFilter = new XXXFilter(); registrationBean.setFilter(xxxFilter); List<String> urls = new ArrayList<>(); //url mapping urls.add("/*"); registrationBean.setUrlPatterns(urls); return registrationBean; } }
自定义拦截器
特点和局限
-
既可以拿到原始的http请求和响应, 也可以拿到真正处理请求的方法的信息
-
拿不到具体方法被调用时所传入的参数值
关键代码
@Component
public class XXXInterceptor implements HandlerInterceptor{
// 该方法将在Controller处理之前进行调用
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("拦截 - 方法前置处理");
System.out.println("处理类名:" + ((HandlerMethod)handler).getBean().getClass().getName());
System.out.println("方法名:" +((HandlerMethod)handler).getMethod().getName());
// true 表示放行调用处理方法
return true;
}
// 需要 preHandle 返回为true
// 当前请求进行处理之后,也就是Controller 方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("controller 方法处理完了");
//我可以在这里对 modelAndView 做点什么
}
// 需要 preHandle 返回为true
// 该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("拦截 - 请求后置处理");
System.out.println("异常信息:" + ex);
}
}
配置启用
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter{
@Autowired
private XXXInterceptor xxxInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册拦截器
registry.addInterceptor(xxxInterceptor);
}
/* ---------------------我是分隔线------------------------------ */
@Bean
public FilterRegistrationBean xxxFiler() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
XXXFilter xxxFilter = new XXXFilter();
registrationBean.setFilter(xxxFilter);
List<String> urls = new ArrayList<>();
//url mapping
urls.add("/*");
registrationBean.setUrlPatterns(urls);
return registrationBean;
}
}
Aspect增强
特点
- 可以拿到方法被调用时传递进来的参数值
- 拿不到原始的http请求和响应的对象
关键代码
// 定义一个切面并交给Spring容器管理
@Aspect
@Component
public class MyAspect {
//定义切入点(1.在哪些方法上起作用 2.什么时候起作用)
@Around("execution(* com.web.controller.UserController.*(..))")
public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("aspect into");
//方法参数的数组
Object[] args = pjp.getArgs();
int i = 0;
for (Object arg : args) {
System.out.println("方法参数 "+(i++)+" : " + arg);
}
//执行实际方法
Object object = pjp.proceed();
System.out.println("aspect out");
return object;
}
}
3种方式的执行顺序
-
假如同时存在这3种拦截,在整个请求响应中执行顺序如下:
-> Filter -> Interceptor -> ControllerAdvice -> Aspect -> Controller
-
如果发生异常
检测异常的顺序就反过来了
-> Controller -> Aspect -> ControllerAdvice -> Interceptor -> Filter -> tomcat