简介:
Filter会将浏览器对服务器资源的请求先统一拦截,要通过Fliter才能访问到对应资源,访问操作结束后会回到过滤器再响应给浏览器。
定义好一个Fliter后要加上一个@WebFilter注解才会生效,同时,还要指定该过滤器要拦截什么样的请求,urlPatterns="/*"表示拦截所有请求。同时还要在项目的启动类当中加上一个@ServletComponentScan注解,表示支持Servlet组件,因为Filter是javaweb的三大组件之一,不是springboot提供
其中要实现三个方法,init()和destory()方法因为不常用,在Filter接口中对于这两个方法已经有了默认实现,可以不用实现init()和destory方法。
@WebFilter(urlPatterns = "/*")
public class DemoFilter implements Filter {
//只调用一次
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// Filter.super.init(filterConfig);
System.out.println("init方法");
}
@Override //拦截到请求之后调用,调用多次
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("拦截到了请求");
//放行
// filterChain.doFilter(servletRequest,servletResponse);
}
//只调用一次
@Override
public void destroy() {
// Filter.super.destroy();
System.out.println("destroy方法");
}
}
在项目启动类当中
项目结构如下
启动项目后控制台输出如下
在前端页面中进行请求后控制台输出如下
并且前端页面在等待过滤器返回的数据
为了让前端页面正常展示,现在要进行放行,使用Filter提供的FilterChain,直接调用它下面的doFilter方法,需要的请求对象ServletRequest对象和响应对象都已经作为形参传了进来,所以可以直接用。
@Override //拦截到请求之后调用,调用多次
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("拦截到了请求");
//放行
filterChain.doFilter(servletRequest,servletResponse);
}
在停止项目时可以看见Filter的销毁方法的执行
重新启动项目之后可以看见请求放行之后正常显示了出来,
放行之后就会去到Controller当中执行对应操作
放行前可以执行一段逻辑,放行之后也可以执行一段逻辑
@Override //拦截到请求之后调用,调用多次
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("拦截到了请求...放行前逻辑");
//放行
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("拦截到了请求...放行后逻辑");
}
在前端页面进行登录操作之后,后端控制台输出如下,放行前后的操作都有执行
拦截的不同种类
有多个过滤器先后执行时需要在所以的过滤器都放行后才能访问对应资源。
@WebFilter(urlPatterns = "/*")
public class Demo1Filter implements Filter {
@Override //拦截到请求之后调用,调用多次
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("1拦截到了请求...放行前逻辑");
//放行
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("1拦截到了请求...放行后逻辑");
}
}
上面的FilterChain就是一个过滤器列,doFilter方法会放行到下一个过滤器,如果当前是最后一个过滤器就会放行到Web资源当中。此处过滤器的先后顺序是由过滤器类在包里面的先后顺序所决定的,如下就是不同的顺序时的输出。
上面的上个方法都有默认实现,这里根据需要重写。
其中preHandle在Controller之前执行,postHandle在Controller之后执行
其次还要注册配置拦截器 ,其中从写的方法里面的/**表示拦截所有。
实现完后要将其交给IOC容器管理
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override //在目标资源方法前运行,返回true:放行,返回false:不放行
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle...");
return true;
}
@Override //目标资源方法运行后运行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle...");
}
@Override //试图渲染完毕后运行,最后运行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion...");
}
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired //获取到拦截器的bean对象
private LoginCheckInterceptor loginCheckInterceptor;
@Override //用于注册拦截器
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**");
}
}
在后台中看见拦截器中的三个方法都有运行输出
设置返回值为 false时就不会放行
比如登录页面的请求就是不需要拦截的。
常见的拦截配置
在拦截器配置中修改如下,放行login请求
@Override //用于注册拦截器
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**").excludePathPatterns("/login");
}
成功登录
浏览器发出的请求会先被过滤器拦截,然后进入到spring环境,tomcat不识别controller,但是识别servlet,spring的web环境提供了一个非常核心的servlet——DispatchServlet。由DispatchServlet转给Controller,在这之前会先被拦截器拦截执行preHandle方法,根据其返回值决定是否执行Controller方法。
使用Filter和interceptor进行测试,发送查询所有部门的请求
服务器控制台输出如下
可以看出,就和栈一样,后进的反而先出了