一、过滤器

新建如下的 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

结果:

image-20200820151800190

在这个过程中出现了一点问题:

当我们进行下面这种过滤一部分的情况下:

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 后面所有的请求,但是结果是 UserControllerHelloController 都进入了过滤器中:

image-20200820194717715

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

image-20200820194815278

在上面我们使用了注解的方式进行过滤:

@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/888http://localhost:8080/hello

可以看见结果如下:

image-20200820202151954

只是对 user/888 进行拦截了,对 hello 没有进行拦截

三、过滤器与拦截器的对比

我们再将前面的过滤器加入其中,可以得到如下结果:

image-20200820202751525

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

32361-20180530095349427-444141538

评论