拦截器和过滤器

拦截器

对action请求起作用,动态拦截action调用的对象。主要是拦截客户请求并作出相应的处理。

实现原理

基于Java反射机制(动态代理)来实现的。

不依赖servlet容器

触发时机:请求进入servlet后,在进入Controller之前

拦截器和过滤器_第1张图片

拦截器的方法

方法名

说明

preHandle()

此方法将在请求处理之前调用,返回值是Boolean类型。如果返回false,标识请求结束,之后的拦截器和controller都不会执行;如果返回true,则会继续调用下一个拦截器的preHandle()方法。

postHandle()

该方法是在请求处理之后被调用,前提是preHandle()方法的返回值全部为true才能被调用,并且会在Dispatcher Servlet进行视图返回 渲染之前被调用,所以可以在这个方法中对controller处理之后的ModelAndView对象进行操作。

afterCompletion()

该方法是在整个请求结束之后,即在Dispatcher Servlet渲染了对应的视图之后执行,前提是preHandle()方法的返回值全部为true才能被调用。

执行流程图

拦截器和过滤器_第2张图片

 1.根据当前请求,找到HandlerExecutionChain执行链,执行链可以处理当前请求的handler方法以及handler方法的所有拦截器;

2.按顺序执行所有拦截器的preHandle方法;

(1)如果当前拦截器preHandle返回为true,说明放行,则执行下一个拦截器的preHandle方法(2)如果当前拦截器preHandle返回为false,说明不放行,则倒序执行所有已经执行了的拦截器的afterCompletion方法(不执行当前返回false拦截器的afterCompletion方法);

3.所有拦截器都返回true才会执行目标方法;

4.倒序执行所有拦截器的postHandle方法;

5.之前的所有步骤如果有任何异常就不会继续向下执行,但都会直接倒序触发afterCompletion;

6.如何没有任何异常,页面成功渲染完成以后,也会倒序触发afterCompletion方法。

使用拦截器(多个拦截器)

1.创建拦截器类实现HandlerInterceptor接口

(两个拦截器)

public class OneInterceptor implements HandlerInterceptor {
    
    // 处理请求之前执行,controller处理之前
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) {
        String url =String.valueOf(request.getRequestURL()) ;
        System.out.println("1、url=="+url);
        // 放开拦截
        return true;
    }
    
    // 处理请求之后执行,(controller处理之后,DispatcherServlet进行视图渲染之前)
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                           Object o, ModelAndView modelAndView) {
        System.out.println("1、postHandle");
    }
    
    // 响应之后执行(DispatcherServlet进行视图渲染之后,返回前端)
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                                Object o, Exception e) {
        System.out.println("1、afterCompletion");
    }
}
public class TwoInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object o) throws Exception {
        String url =String.valueOf(request.getRequestURL()) ;
        System.out.println("2、url=="+url);
        // 放开拦截
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                           Object o, ModelAndView modelAndView) throws Exception {
        System.out.println("2、postHandle");
    }
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                                Object o, Exception e) throws Exception {
        System.out.println("2、afterCompletion");
    }
}

2.注入拦截器

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 拦截所有路径
        // 注册自定义两个拦截器
        registry.addInterceptor(new OneInterceptor()).addPathPatterns("/**");
        registry.addInterceptor(new TwoInterceptor()).addPathPatterns("/**");
    }

}

3.测试,访问路径

@RequestMapping("/reqUrl")
    public void reqUrl () {
        System.out.println("目标方法执行....");
    }

拦截器和过滤器_第3张图片

 Filter过滤器

实现原理

基于函数回调

依赖servlet容器,在进入tomcat容器之后,进入servlet之前执行

方法

init() :该方法在容器启动初始化过滤器时被调用,它在 Filter 的整个生命周期只会被调用一次。

doFilter() :容器中的每一次请求都会调用该方法, FilterChain 用来调用下一个过滤器 Filter。

destroy(): 当容器销毁过滤器实例时调用该方法,一般在方法中销毁或关闭资源,在过滤器 Filter 的整个生命周期也只会被调用一次

public class MyFilter implements Filter {
 
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

        System.out.println("Filter 前置");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        System.out.println("Filter 处理中");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

        System.out.println("Filter 后置");
    }
}

使用

Filter流程图:

用户登录

拦截器和过滤器_第4张图片

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
    HttpSession session = httpServletRequest.getSession();
    Object user = session.getAttribute("user");
    // 如果 user = null; 说明 user 还没有登陆
    if (user == null) {
        httpServletRequest.getRequestDispatcher("/xxxx").forward(httpServletRequest,servletResponse);
        return;     
    } else {
        // 让程序继续往下访问用户的目标资源
        filterChain.doFilter(servletRequest,servletResponse);
    }
}

FilterChain过滤器链

执行流程:

拦截器和过滤器_第5张图片

 多个Filter执行顺序

1.在web.xml中,filter执行顺序跟的顺序有关,先声明的先执行

2.使用注解配置的话,filter的执行顺序跟名称的字母顺序有关,例如AFilter会比BFilter先执行

3.如果既有在web.xml中声明的Filter,也有通过注解配置的Filter,那么会优先执行web.xml中配置的Filter

你可能感兴趣的:(编程,java)