一、过滤器
新建如下的 Controller:
1 2 3 4 5 6 7 8 9
| @RestController public class UserController {
@GetMapping("user/{id}") public void get(@PathVariable String id) { System.out.println(id); }
}
|
过滤器的实现:定义一个类实现 Filter ,并重写其中的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @Component @WebFilter(urlPatterns = "/*") public class TimeFilter implements Filter {
@Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("Initialization"); }
@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("++++++++ Start ++++++++"); Long start = new Date().getTime(); filterChain.doFilter(servletRequest, servletResponse); System.out.println("Filter costs: "); System.out.println(new Date().getTime() - start); System.out.println("++++++++ End ++++++++"); }
@Override public void destroy() { System.out.println("Filter is over"); } }
|
init 方法:是对项目启动时,进行的初始化
doFilter 方法:当执行一个请求的时候,进行过滤
destroy 方法:当这个项目关闭时,该过滤器也被销毁了
浏览器运行:http://localhost:8080/user/666
结果:

在这个过程中出现了一点问题:
当我们进行下面这种过滤一部分的情况下:
TimeFilter
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
| @Component @WebFilter(urlPatterns = {"/user/*"}) public class TimeFilter implements Filter {
@Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println(filterConfig.getServletContext().getContextPath()); System.out.println("Initialization........"); }
@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("++++++++ Start ++++++++"); Long start = new Date().getTime(); filterChain.doFilter(servletRequest, servletResponse); System.out.println("Filter costs: "); System.out.println(new Date().getTime() - start); System.out.println("++++++++ End ++++++++"); }
@Override public void destroy() { System.out.println("Filter is over"); } }
|
UserController
1 2 3 4 5 6 7 8 9
| @RestController public class UserController {
@GetMapping("user/{id}") public void get(@PathVariable String id) { System.out.println("userID:" +id); }
}
|
HelloController
1 2 3 4 5 6 7 8
| @RestController public class HelloController {
@RequestMapping("hello") public String hello() { return "hello"; } }
|
此时我们过滤的是 /user 后面所有的请求,但是结果是 UserController 和 HelloController 都进入了过滤器中:

最终解决方案:去掉在 TimeFilter 中的 @Component 注解,在启动类上加上 @ServletComponentScan 注解即可:

在上面我们使用了注解的方式进行过滤:
@WebFilter(urlPatterns = “/*”)
第二种方式:
去掉 @Component 和 *@WebFilter(urlPatterns = {“/user/“})** 注解,并配置如下的配置类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Configuration public class WebConfig { @Bean public FilterRegistrationBean timeFilter() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); TimeFilter timeFilter = new TimeFilter(); filterRegistrationBean.setFilter(timeFilter);
List<String> urlList = new ArrayList<>(); urlList.add("/user/*");
filterRegistrationBean.setUrlPatterns(urlList); return filterRegistrationBean; } }
|
二、拦截器
编写一个拦截器类实现 HandlerInterceptor ,如下:
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
| public class TimeInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("处理拦截之前"); request.setAttribute("startTime", new Date().getTime()); System.out.println(((HandlerMethod) handler).getBean().getClass().getName()); System.out.println(((HandlerMethod) handler).getMethod().getName()); return true; }
@Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("开始处理拦截"); Long start = (Long) request.getAttribute("startTime"); System.out.println("【拦截器】耗时 " + (new Date().getTime() - start)); }
@Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("处理拦截之后"); Long start = (Long) request.getAttribute("startTime"); System.out.println("【拦截器】耗时 " + (new Date().getTime() - start)); System.out.println("异常信息 " + ex); } }
|
preHandle 方法在处理拦截之前执行
postHandle 方法只有当被拦截的方法没有抛出异常成功时才会处理
afterCompletion 方法无论被拦截的方法抛出异常与否都会执行
将我们写好的拦截器注册到容器中:
1 2 3 4 5 6 7 8 9 10 11 12
| @Configuration public class InterceptorConfig implements WebMvcConfigurer {
@Autowired TimeInterceptor timeInterceptor;
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(timeInterceptor).addPathPatterns("/user/*"); } }
|
同样分别运行:http://localhost:8080/user/888 和 http://localhost:8080/hello
可以看见结果如下:

只是对 user/888 进行拦截了,对 hello 没有进行拦截
三、过滤器与拦截器的对比
我们再将前面的过滤器加入其中,可以得到如下结果:

有一张已经整理好执行顺序图:
