Java过滤器(Filter)使用详解

一、过滤器基础概念

1. 什么是过滤器

过滤器(Filter)是Java Web中的一种组件,可以在请求到达Servlet之前或响应返回客户端之前对HTTP请求和响应进行预处理和后处理。

2. 过滤器的作用

  • 认证和授权:检查用户是否登录,是否有权限访问资源

  • 日志记录:记录请求和响应信息

  • 数据压缩:压缩响应数据

  • 字符编码转换:统一请求和响应的编码

  • 数据加密/解密:对敏感数据进行处理

  • XSS防护:过滤恶意脚本

3. 过滤器的工作原理

客户端请求 → 过滤器1 → 过滤器2 → ... → Servlet → 过滤器2 → 过滤器1 → 客户端响应

二、过滤器的创建与配置

1. 创建过滤器类

实现javax.servlet.Filter接口:

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter("/*") // 过滤所有请求
public class MyFilter implements Filter {
    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化方法,在过滤器创建时调用
        System.out.println("过滤器初始化...");
    }
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // 过滤处理方法
        System.out.println("请求到达过滤器...");
        
        // 预处理代码
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        
        // 放行到下一个过滤器或目标资源
        chain.doFilter(request, response);
        
        // 后处理代码
        System.out.println("响应经过过滤器...");
    }
    
    @Override
    public void destroy() {
        // 销毁方法,在过滤器销毁时调用
        System.out.println("过滤器销毁...");
    }
}

2. 配置过滤器的两种方式

方式一:注解配置(Servlet 3.0+)
@WebFilter(
    urlPatterns = {"/user/*", "/admin/*"},  // 过滤路径
    initParams = {
        @WebInitParam(name = "encoding", value = "UTF-8"),
        @WebInitParam(name = "key", value = "value")
    },
    dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.FORWARD}
)
public class MyFilter implements Filter {
    // ...
}
方式二:web.xml配置
<filter>
    <filter-name>myFilter</filter-name>
    <filter-class>com.example.MyFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>myFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

三、过滤器的核心方法详解

1. init(FilterConfig config)

  • 在过滤器实例创建后立即调用

  • 用于初始化过滤器的配置参数

  • FilterConfig对象可以获取初始化参数和ServletContext

    @Override
    public void init(FilterConfig filterConfig) {
        String encoding = filterConfig.getInitParameter("encoding");
        this.encoding = encoding != null ? encoding : "UTF-8";
        this.servletContext = filterConfig.getServletContext();
    }

    2. doFilter(ServletRequest, ServletResponse, FilterChain)

  • 每次请求都会调用该方法

  • 核心过滤逻辑写在这里

  • 必须调用chain.doFilter()方法将请求传递给下一个过滤器或目标资源

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) 
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        
        // 预处理
        System.out.println("拦截到请求: " + request.getRequestURI());
        long startTime = System.currentTimeMillis();
        
        // 放行
        chain.doFilter(request, response);
        
        // 后处理
        long endTime = System.currentTimeMillis();
        System.out.println("请求处理耗时: " + (endTime - startTime) + "ms");
    }

    3. destroy()

  • 在过滤器实例销毁前调用

  • 用于释放资源

    @Override
    public void destroy() {
        // 清理资源
        this.encoding = null;
        this.servletContext = null;
    }

四、过滤器的高级应用

1. 多过滤器执行顺序

多个过滤器的执行顺序:

  1. web.xml中<filter-mapping>的配置顺序

  2. 注解配置时按过滤器类名的字母顺序

可以通过@Order注解指定顺序(Spring环境中):

@Order(1)
@WebFilter("/*")
public class FilterA implements Filter { /*...*/ }

@Order(2)
@WebFilter("/*")
public class FilterB implements Filter { /*...*/ }

2. 拦截不同类型的请求

通过dispatcherTypes属性可以指定拦截的请求类型:

@WebFilter(
    urlPatterns = "/*",
    dispatcherTypes = {
        DispatcherType.REQUEST,      // 直接请求
        DispatcherType.FORWARD,      // 转发
        DispatcherType.INCLUDE,      // 包含
        DispatcherType.ERROR,        // 错误
        DispatcherType.ASYNC         // 异步
    }
)

3. 防止XSS攻击的过滤器示例

@WebFilter("/*")
public class XssFilter implements Filter {
    
    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(request);
        chain.doFilter(xssRequest, resp);
    }
    
    // XSS请求包装类
    public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
        public XssHttpServletRequestWrapper(HttpServletRequest request) {
            super(request);
        }
        
        @Override
        public String getParameter(String name) {
            return cleanXSS(super.getParameter(name));
        }
        
        @Override
        public String[] getParameterValues(String name) {
            String[] values = super.getParameterValues(name);
            if (values == null) return null;
            String[] cleanedValues = new String[values.length];
            for (int i = 0; i < values.length; i++) {
                cleanedValues[i] = cleanXSS(values[i]);
            }
            return cleanedValues;
        }
        
        private String cleanXSS(String value) {
            if (value == null) return null;
            return value.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
        }
    }
}

4. 登录验证过滤器示例

@WebFilter("/admin/*")
public class LoginFilter implements Filter {
    
    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        HttpSession session = request.getSession(false);
        
        String loginURI = request.getContextPath() + "/login";
        
        boolean loggedIn = session != null && session.getAttribute("user") != null;
        boolean loginRequest = request.getRequestURI().equals(loginURI);
        
        if (loggedIn || loginRequest) {
            chain.doFilter(request, response);
        } else {
            response.sendRedirect(loginURI);
        }
    }
}

五、常见问题与解决方案

1. 过滤器不生效的可能原因

  • 过滤器类没有实现javax.servlet.Filter接口

  • 没有配置@WebFilter注解或web.xml配置错误

  • URL模式不匹配当前请求路径

  • 过滤器抛出了异常没有正确处理

  • doFilter方法中没有调用chain.doFilter()

2. 获取不到HttpServletRequest对象

需要将ServletRequest强制转换为HttpServletRequest:

HttpServletRequest httpRequest = (HttpServletRequest) request;

3. 过滤器中的异常处理

@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) {
    try {
        // 预处理
        chain.doFilter(req, resp);
        // 后处理
    } catch (Exception e) {
        // 处理异常
        ((HttpServletResponse) resp).sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
    }
}

4. 性能监控过滤器示例

@WebFilter("/*")
public class PerformanceFilter implements Filter {
    
    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws IOException, ServletException {
        long startTime = System.currentTimeMillis();
        chain.doFilter(req, resp);
        long endTime = System.currentTimeMillis();
        
        HttpServletRequest request = (HttpServletRequest) req;
        System.out.printf("%s 请求 %s 耗时 %d ms%n",
                request.getMethod(),
                request.getRequestURI(),
                (endTime - startTime));
    }
}

六、Spring Boot中的过滤器

在Spring Boot中使用过滤器:

1. 使用@WebFilter注解

@WebFilter(urlPatterns = "/*")
public class MySpringFilter implements Filter {
    // 实现方法
}

需要在启动类添加@ServletComponentScan注解:

@SpringBootApplication
@ServletComponentScan
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

2. 使用FilterRegistrationBean注册

@Configuration
public class FilterConfig {
    
    @Bean
    public FilterRegistrationBean<MyFilter> myFilterRegistration() {
        FilterRegistrationBean<MyFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new MyFilter());
        registration.addUrlPatterns("/*");
        registration.setName("myFilter");
        registration.setOrder(1); // 设置顺序
        return registration;
    }
}

3. Spring Security中的过滤器链

Spring Security本身就是基于过滤器链实现的,了解其过滤器顺序有助于自定义过滤器:

  1. ChannelProcessingFilter

  2. SecurityContextPersistenceFilter

  3. ConcurrentSessionFilter

  4. 认证处理过滤器(UsernamePasswordAuthenticationFilter等)

  5. SecurityContextHolderAwareRequestFilter

  6. RememberMeAuthenticationFilter

  7. AnonymousAuthenticationFilter

  8. ExceptionTranslationFilter

  9. FilterSecurityInterceptor


七、最佳实践

  1. 合理设计过滤器链:将功能单一化,每个过滤器只处理一件事情

  2. 注意性能影响:过滤器中避免耗时操作

  3. 异常处理:确保过滤器中的异常被正确处理

  4. 线程安全:过滤器是单例的,注意实例变量的线程安全

  5. 合理设置过滤路径:避免过度拦截影响性能

  6. 日志记录:重要的过滤操作应该记录日志

  7. 与拦截器区分:在Spring环境中,简单功能用拦截器,Servlet相关用过滤器


八、总结

过滤器是Java Web开发中非常重要的组件,它提供了一种声明式的处理HTTP请求和响应的机制。通过本文的详细介绍,你应该已经掌握了:

  1. 过滤器的基本概念和工作原理

  2. 如何创建和配置过滤器

  3. 过滤器的核心方法和生命周期

  4. 过滤器的高级应用场景

  5. 常见问题解决方案

  6. Spring Boot中的过滤器使用

  7. 过滤器的最佳实践

合理使用过滤器可以大大提高Web应用的安全性、可维护性和性能。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值