Java过滤器与拦截器详解:功能、应用与区别

Java开发中,过滤器(Filter)和拦截器(Interceptor)是两种常用的功能扩展机制,它们可以对请求或响应进行预处理或后处理。尽管它们在某些场景下的作用类似,但在实现方式和应用场景上又有显著的区别。本文将详细讲解Java过滤器与拦截器的概念、实现方式、应用场景,并通过代码示例帮助理解。

一、Java过滤器(Filter)

1.1 什么是过滤器?

过滤器是一种Servlet技术,它主要用于在客户端请求到达Servlet之前、或者在Servlet生成响应返回客户端之前,对请求或响应进行预处理或后处理。过滤器的典型应用场景包括记录日志、权限验证、请求参数编码、压缩响应数据等。

1.2 过滤器的工作原理

过滤器的工作原理是基于Java EE中的Servlet规范。每个请求在到达Servlet之前,会先经过配置好的过滤器链,过滤器可以根据需要对请求进行修改或处理。处理完毕后,过滤器可以选择继续将请求传递给下一个过滤器或目标Servlet,也可以中断请求处理。

1.3 过滤器的生命周期

过滤器的生命周期包括初始化(init)、执行(doFilter)和销毁(destroy)三个阶段:

  • init: 过滤器初始化时调用,通常用于资源的初始化操作。
  • doFilter: 每个请求都会调用该方法,用于具体的请求或响应处理。
  • destroy: 当过滤器被销毁时调用,用于释放资源。

1.4 过滤器的实现步骤

要实现一个Java过滤器,通常需要以下几个步骤:

  1. 创建过滤器类:实现javax.servlet.Filter接口。
  2. 重写initdoFilterdestroy方法
  3. 配置过滤器:在web.xml中配置过滤器,或者使用注解@WebFilter

1.5 代码示例

以下是一个简单的过滤器实现

package com.baidu.filter;

import com.alibaba.fastjson.JSONObject;
import com.baidu.pojo.Result;
import com.baidu.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Slf4j
@WebFilter(urlPatterns = "/*")
public class DemoFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        //1.获取请求参数url
        String url = req.getRequestURI().toString();
        log.info("请求路径:{}",url);
        //2.判断url中是否包含login,包含则放行
        if (url.contains("login")){
            log.info("登录操作,放行");
            chain.doFilter(request,response);
            return;
        }
        //3,获取请求头当中的令牌
        String jwt = req.getHeader("token");
        //4.判断令牌是否存在,不存在则返回错误信息(未登录)
        if(!StringUtils.hasLength(jwt)){
            log.info("未登录");
            Result error = Result.error("NOT_LOGIN");
            //将相应的数据转换为json格式
            String notlogin = JSONObject.toJSONString(error);
            resp.getWriter().write(notlogin);
            return;
        }
        //5.存在则校验令牌是否正确,正确则放行,不正确则返回错误信息(未登录)
        try {
            JwtUtils.parseJwt(jwt);
        } catch (Exception e) {
            e.printStackTrace();
            log.info("令牌错误");
            Result error = Result.error("NOT_LOGIN");
            //将相应的数据转换为json格式
            String notlogin = JSONObject.toJSONString(error);
            resp.getWriter().write(notlogin);
            return;
        }
        log.info("令牌正确,放行");
        chain.doFilter(request,response);

    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

在上面的代码中,首先判断用户的请求是否为登录请求,如果是则放行,不是则判断是否有令牌,如果有令牌且令牌合法,则放行。

1.6 过滤器的应用场景

过滤器广泛应用于以下场景:

  • 日志记录:记录每个请求的访问日志,包括请求路径、参数、响应时间等。
  • 权限验证:在请求到达Servlet之前进行用户权限检查,如果没有权限可以直接返回错误响应。
  • 请求参数编码:统一处理请求参数的字符编码,避免出现乱码。
  • 响应数据压缩:在返回响应之前对数据进行GZIP压缩,减少传输的数据量。

二、Java拦截器(Interceptor)

2.1 什么是拦截器?

拦截器是一种AOP(面向切面编程)技术,主要用于在方法调用前后进行处理。Java中的拦截器通常与Spring框架一起使用,可以在控制器(Controller)方法执行前后或抛出异常时执行自定义逻辑。拦截器通常用于记录日志、权限校验、事务管理等。

2.2 拦截器的工作原理

拦截器是通过代理模式实现的,Spring MVC中的拦截器链类似于过滤器链。每个请求在到达Controller之前,都会经过配置的拦截器,拦截器可以根据需要对请求进行处理,甚至可以决定是否继续传递请求。

2.3 拦截器的生命周期

拦截器的生命周期与请求处理的阶段密切相关:

  • preHandle: 在请求到达Controller方法之前调用,用于处理前置逻辑。如果返回false,则请求不会继续传递。
  • postHandle: 在Controller方法执行之后,视图渲染之前调用,用于处理后置逻辑。
  • afterCompletion: 在整个请求处理完毕后调用,包括视图渲染完成或抛出异常时,用于资源清理或日志记录。

2.4 拦截器的实现步骤

要实现一个Java拦截器,通常需要以下几个步骤:

  1. 创建拦截器类:实现HandlerInterceptor接口。
  2. 重写preHandlepostHandleafterCompletion方法
  3. 配置拦截器:在Spring配置文件中配置拦截器,或者使用注解配置。

2.5 代码示例

以下是一个简单的拦截器实现,用于检查用户是否登录:

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
       throws Exception {
        // 检查用户是否登录
        Object user = request.getSession().getAttribute("user");
        if (user == null) {
            // 未登录,重定向到登录页面
            response.sendRedirect("/login");
            return false;
        }
        return true; // 继续执行下一个拦截器或目标方法
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {
        // 处理后置逻辑
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,Exception ex) throws Exception {
        // 资源清理或日志记录
    }
}

在这个示例中,AuthInterceptor拦截器会在每次请求时检查用户是否已经登录,如果未登录则重定向到登录页面。

package com.baidu.interceptor;

import com.alibaba.fastjson.JSONObject;
import com.baidu.pojo.Result;
import com.baidu.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
@Slf4j
public class LoginCheck implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {
        //1.获取请求参数url
        String url = req.getRequestURI().toString();
        log.info("请求路径:{}",url);
        //3,获取请求头当中的令牌
        String jwt = req.getHeader("token");
        //4.判断令牌是否存在,不存在则返回错误信息(未登录)
        if(!StringUtils.hasLength(jwt)){
            log.info("未登录");
            Result error = Result.error("NOT_LOGIN");
            //将相应的数据转换为json格式
            String notlogin = JSONObject.toJSONString(error);
            resp.getWriter().write(notlogin);
            return false;
        }
        //5.存在则校验令牌是否正确,正确则放行,不正确则返回错误信息(未登录)
        try {
            JwtUtils.parseJwt(jwt);
        } catch (Exception e) {
            e.printStackTrace();
            log.info("令牌错误");
            Result error = Result.error("NOT_LOGIN");
            //将相应的数据转换为json格式
            String notlogin = JSONObject.toJSONString(error);
            resp.getWriter().write(notlogin);
            return false;
        }
        log.info("令牌正确,放行");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

配置类:

package com.baidu.config;

import com.baidu.interceptor.LoginCheck;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private LoginCheck loginCheck;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginCheck).addPathPatterns("/**")
                .excludePathPatterns("/login.html","/login","/css/**","/js/**","/images/**");
    }
}

2.6 拦截器的应用场景

拦截器主要用于以下场景:

  • 权限校验:在Controller方法执行之前进行用户权限检查,未授权的请求会被拦截。
  • 日志记录:记录Controller方法的执行时间、请求参数和响应数据等。
  • 事务管理:在方法执行前开启事务,在方法执行后提交事务,在异常时回滚事务。
  • 全局异常处理:捕获Controller方法抛出的异常,并进行统一处理或记录。

三、过滤器与拦截器的区别

尽管过滤器和拦截器在某些场景下可以互换使用,但它们在实现方式、应用层次和使用场景上存在显著区别。

3.1 实现方式

  • 过滤器基于Servlet规范,实现javax.servlet.Filter接口,工作在Servlet容器层级。
  • 拦截器基于Spring框架,实现HandlerInterceptor接口,工作在Spring MVC框架层级。

3.2 应用层次

  • 过滤器一般在整个Web应用的最外层进行处理,它可以过滤所有请求,包括静态资源(如CSS、JS、图片等)。
  • 拦截器主要用于拦截Controller方法调用,通常只对动态请求起作用。

3.3 使用场景

  • 过滤器适用于请求的全局预处理,例如日志记录、编码处理、跨域设置等。
  • 拦截器适用于业务逻辑的前置或后置处理,例如权限验证、事务管理等。

3.4 代码配置

  • 过滤器可以在web.xml中配置,也可以使用@WebFilter注解。
  • 拦截器一般在Spring的配置文件中配置,也可以使用@Configuration类中注册。

3.5 性能影响

  • 过滤器在Servlet容器级别运行,通常性能开销较低,但由于处理的是所有请求,配置不当可能影响整体性能。
  • 拦截器在Spring容器级别运行,性能开销取决于Spring容器的管理,通常与业务逻辑绑定紧密。

四、总结

通过以上分析可以看出,过滤器和拦截器在Java Web开发中各有其独特的作用,我们应该根据需求来选择。

  • 19
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nkion

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值