Spring Boot自定义拦截器
概要
HandlerInterceptor介绍
spring boot自定义拦截器实现
HandlerInterceptor介绍
Spring提供的拦截器Interceptor与Servlet中的Filter不同的是, Interceptor采用AOP的方式在Servlet的service方法执行之前进行拦截, 可以进行更精细的控制
Interceptor中有如下方法:
- preHandle: 在Controller处理之前调用, 返回false时整个请求结束
- postHandle: 在Controller调用之后执行, 但它会在DispatcherServlet进行视图的渲染之前执行, 也就是说在这个方法中你可以对ModelAndView进行操作
- afterCompletion: 在整个请求完成之后执行, 也就是DispatcherServlet已经渲染了视图之后执行; 这个方法的主要作用是用于清理资源的
- afterConcurrentHandlingStarted: 这个方法是AsyncHandlerInterceptor接口中添加的. 当Controller中有异步请求方法的时候会触发该方法, 异步请求先支持preHandle、然后执行afterConcurrentHandlingStarted, 异步线程完成之后执行会再执行preHandle、postHandle、afterCompletion
关于最后那个方法, 举个列子:上面这样的Controller里面有个异步结果, 则拦截器的执行顺序将是: preHandle -> afterConcurrentHandlingStarted -> preHandle -> postHandle -> afterCompletion.1
2
3
4
5
6
7
8
9
public class ExampleController {
"/") (
DeferredResult<String> home() {
DeferredResult<String> dr = new DeferredResult<String>();
dr.setResult("成功");
return dr;
}
}
如果把dr.setResult(“成功”); 这句删掉, 将只执行preHandle -> afterConcurrentHandlingStarted
可以认为, afterConcurrentHandlingStarted是返回异步结果时调用(此时异步结果里不需要有数据), 而postHandle必须是返回的结果执行完, 异步结果中有数据了(dr.setResult)才调用
spring boot自定义拦截器实现
- 拦截器的编写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43public class AuthInterceptor extends HandlerInterceptorAdapter {
/**
* 前置检查
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!handler.getClass().isAssignableFrom(HandlerMethod.class)) {
return true;
}
String ip = request.getRemoteAddr();
long startTime = System.currentTimeMillis();
request.setAttribute("requestStartTime", startTime);
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
System.out.println("用户:" + ip + ",访问目标:" + method.getDeclaringClass().getName() + "." + method.getName());
return true;
}
/**
* Controller调用之后执行
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
long startTime = (Long) request.getAttribute("requestStartTime");
long endTime = System.currentTimeMillis();
long executeTime = endTime - startTime;
// log it
if (executeTime > 1000) {
System.out.println("[" + method.getDeclaringClass().getName() + "." + method.getName() + "] 执行耗时 : "
+ executeTime + "ms");
} else {
System.out.println("[" + method.getDeclaringClass().getSimpleName() + "." + method.getName() + "] 执行耗时 : "
+ executeTime + "ms");
}
}
} - 创建配置类继承WebMvcConfigurerAdapter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class AuthHandlerAdapter extends WebMvcConfigurerAdapter {
/**
* 拦截器
* 由于项目集成了swagger,这里直接不拦截swagger的相关请求
*/
public void addInterceptors(InterceptorRegistry registry) {
//AuthInterceptor就是我们自定义的拦截器
registry.addInterceptor(new AuthInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/swagger-ui.html")
.excludePathPatterns("/swagger-resources/**")
.excludePathPatterns("/v2/api-docs");
}
/**
* 资源处理器
* swagger会和freemarker的静态资源路径冲突因此需配置swagger的资源处理器
*/
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}