Java拦截器和过滤器的区别

251 阅读4分钟

区别

Interceptor

Filter

应用范围

拦截器是Web框架中的一部分,例如Spring MVC框架,用于拦截请求和响应,可以在方法调用之前和之后执行指定的操作过滤器是Servlet规范的一部分,可以在请求进入Servlet容器之前或者离开容器之后进行处理。

处理顺序

拦截器是基于Java的反射机制,在方法调用前后进行拦截,可以自定义拦截顺序。过滤器是根据元素在web.xml文件中的顺序来决定的。

生命周期

拦截器是在每次请求时都会创建新的实例,并在处理完成后销毁而过滤器是在应用启动时创建,并在应用关闭时销毁。

功能

拦截器主要用于拦截和处理请求和响应,例如日志记录、权限验证等过滤器主要用于过滤请求和响应,例如对请求进行字符编码、防止跨站点脚本攻击等。

总的来说,拦截器更加灵活和强大,可以作用于具体的方法调用,对请求和响应进行处理。

过滤器更加通用,可以对请求进行过滤和预处理,不局限于某个具体的方法。

案例

我们假设有一个Web应用,其中包含一个登录功能。

当用户登录成功后,需要记录用户的登录信息,并在每个请求中验证用户是否已登录。

首先,可以使用拦截器来实现这个功能。在用户登录成功后记录登录信息,并在每个请求之前验证用户是否已登录。以下是拦截器的示例代码:

    public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 在请求之前进行处理,判断用户是否已登录
        if (userIsLoggedIn()) {
            // 用户已登录,继续处理请求
            return true;
        } else {
            // 用户未登录,跳转到登录页面
            response.sendRedirect("/login");
            return false;
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 在请求之后进行处理,记录用户登录信息
        logUserLoginInfo();
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 请求完成之后进行处理
    }

    private boolean userIsLoggedIn() {
        // 判断用户是否已登录的逻辑
        // ...
    }

    private void logUserLoginInfo() {
        // 记录用户登录信息的逻辑
        // ...
    }
}

然后,可以在配置文件中将拦截器应用到特定的URL路径上,例如

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/secure/**");
    }
}

在上述例子中,通过拦截器实现了在用户登录成功后记录登录信息,并在每个请求中验证用户是否已登录。

接下来,也可以使用过滤器来实现相同的功能:

    public class LoginFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 过滤器的初始化逻辑
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        
        // 在请求之前进行处理,判断用户是否已登录
        if (userIsLoggedIn(httpRequest)) {
            // 用户已登录,继续处理请求
            chain.doFilter(request, response);
        } else {
            // 用户未登录,跳转到登录页面
            httpResponse.sendRedirect(httpRequest.getContextPath() + "/login");
        }

        // 在请求之后进行处理,记录用户登录信息
        logUserLoginInfo(httpRequest);
    }

    @Override
    public void destroy() {
        // 过滤器的销毁逻辑
    }

    private boolean userIsLoggedIn(HttpServletRequest request) {
        // 判断用户是否已登录的逻辑
        // ...
    }

    private void logUserLoginInfo(HttpServletRequest request) {
        // 记录用户登录信息的逻辑
        // ...
    }
}

通过这个例子,可以看到使用拦截器和过滤器都能够实现相似的功能,都可以在请求前后进行处理。

拦截器更适合在业务逻辑层面进行拦截和处理,而过滤器更适合在Web容器层面进行拦截和处理。

可以根据具体的需求和框架选择合适的方法来实现功能。

执行顺序

如果拦截器和过滤器同时使用,那么他们执行的顺序谁先谁后呢?

在Java Web应用中,拦截器和过滤器的执行顺序如下:

  1. 过滤器先于拦截器执行。
  2. 拦截器在进入处理器(Controller)之前执行。
  3. 拦截器在离开处理器之后执行。
  4. 过滤器在进入目标资源之前执行。
  5. 过滤器在离开目标资源之后执行。

具体的执行顺序如下:

  1. 过滤器的doFilter()方法被调用。

  2. 拦截器的 preHandle()方法被调用。

  3. 控制器的处理方法执行。

  4. 拦截器的postHandle()方法被调用。

  5. 视图渲染之前,拦截器的afterCompletion()方法被调用。

  6. 过滤器的doFilter()方法继续执行。

在过滤器和拦截器同时使用的情况下,过滤器先于拦截器执行,而拦截器则在进入和离开处理器之前执行

这样可以先进行一些通用的请求过滤或修改,然后再执行特定操作。

拦截器则专注于处理器的执行过程,例如记录日志、权限验证等。

通过组合使用过滤器和拦截器,可以实现更加灵活和全面的请求处理机制。