JavaWeb 中的 Filter组件详解

2025-11-27 19:50
文章标签 java web filter 详解 组件

本文主要是介绍JavaWeb 中的 Filter组件详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《JavaWeb中的Filter组件详解》本文详细介绍了JavaWeb中的Filter组件,包括其基本概念、工作原理、核心接口和类、配置方式以及常见应用示例,Filter可以实现请求预处理、响应后...

JavaWeb 中的 Filter 详解

1. Filter 基本概念

1.1 什么是 Filter

Filter(过滤器)是 JavaWeb 中的一种组件,用于在请求到达 Servlet 之前或响应发送到客户端之前对请求和响应进行预处理和后处理。

1.2 Filter 的作用

  • 请求预处理:在请求到达 Servlet 之前进行处理
  • 响应后处理:在响应发送到客户端之前进行处理
  • 链式处理:多个 Filter 可以形成处理链
  • 动态拦截:根据条件决定是否继续执行

2. Filter 的工作原理

2.1 Filter 生命周期

public class MyFilter implements Filter {
    // 1. 初始化方法 - 容器启动时调用
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("Filter 初始化");
    }
    // 2. 过滤方法 - 每次请求时调用
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        // 前置处理
        System.out.println("请求到达 Filter");
        // 传递给下一个 Filter 或 Servlet
        chain.doFilter(request, response);
        // 后置处理
        System.out.println("响应经过 Filter");
    }
    // 3. 销毁方法 - 容器关闭时调用
    @Override
    public void destroy() {
        System.out.println("Filter 销毁");
    }
}

2.2 Filter 执行流程

客户端请求 → Filter1 → Filter2 → ... → Servlet → Filter2 → Filter1 → 客户端响应

3. Filter 的核心接口和类

3.1 Filter 接口

public interface Filter {
    void init(FilterConfig filterConfig);
    void doFilter(ServletRequest request, ServletResponse response, 
                 FilterChain chain);
    void destroy();
}

3.2 FilterConfig 接口

public interface FilterConfig {
    String getFilterName();
    ServletContext getServletContext();
    String getInitParameter(String name);
    Enumeration<String> getInitParameterNames();
}

3.3 FilterChain 接口

public interface FilterChain {
    void doFilter(ServletRequest request, ServletResponse response);
}

4. Filter 的配置方式

4.1 注解配置(推荐)

@WebFilter(
    filterName = "myFilter",
    urlPatterns = {"/*"},
    initParams = {
        @WebInitParam(name = "encoding", value = "UTF-8"),
        @WebInitParam(name = "excludePaths", value = "/static/*")
    }
)
public class MyFilter implements Filter {
    // Filter 实现
}

4.2 web.xml 配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         version="3.1">
    <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&gwww.chinasem.cnt;
    <filter-mapping>
        <filter-name>myFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>
</web-app>

5. 常用 Filter 实现示例

5.1 字符编码过滤器

@WebFilter(
    urlPatterns = "/*",
    initParams = @WebInitParam(name = "encoding", value = "UTF-8")
)
public class CharacterEncodingFilter implements Filter {
    private String encoding = "UTF-8";
    @Override
    public void init(FilterConfig filterConfig) {
        String encodingParam = filterConfig.getInitParameter("encoding");
        if (encodingParam != null && !encodingParam.isEmpty()) {
            this.encoding = encodingParam;
        }
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        // 设置请求编码
        request.setCharacterEncoding(encoding);
        // 设置响应编码
        response.setCharacterEncoding(encoding);
        response.setContentType("text/html;charset=" + encoding);
        System.out.println("设置字符编码: " + encoding);
        chain.doFilter(request, response);
    }
    @Override
    public void destroy() {
        // 清理资源
    }
}

5.2 身份认证过滤器

@WebFilter(urlPatterns = {"/admin/*", "/user/*"})
public class AuthenticationFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        HttpSession session = httpRequest.getSession(false);
        // 检查用户是否登录
        if (session == null || session.getAttribute("user") == null) {
            // 未登录,重定向到登录页面
            httpResponse.sendRedirect(httpRequest.getContextPath() + "/login");
            return;
        }
        // 检查用户权限
        User user = (User) session.getAttribute("user");
        String requestURI = httpRequest.getRequestURI();
    python    if (requestURI.contains("/admin/") && !user.isAdmin()) {
            httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "权限不足");
            return;
        }
        System.out.println("用户 " + user.getUsername() + " 访问: " + requestURI);
        chain.doFilter(request, response);
    }
}

5.3 日志记录过滤器

@WebFilter("/*")
public class LoggingFilter implements Filter {
    private static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class);
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        long startTime = System.currentTimeMillis();
        // 记录请求信息
        String clientIP = getClientIP(httpRequest);
        String requestURI = httpRequest.getRequestURI();
        String method = httpRequest.getMethod();
        logger.info("请求开始: {} {} from {}", method, requestURI, clientIP);
        try {
            chain.doFilter(request, response);
        } finally {
            // 记录响应信息
            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            int status = httpResponse.getStatus();
            logger.info("请求完成: {} {} - 状态: {} - 耗时: {}ms", 
                       method, requestURI, status, duration);
        }
    }
    private String getClientIP(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
            return xForwardedFor.split(",")[0];
        }
        return request.getRemoteAddr();
    }
}

5.4 跨域过滤器 (CORS)

@WebFilter("/*")
public class CorsFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        // 设置 CORS 头
        httpResponse.setHeader("Access-Control-Allow-Origin", "*");
        httpResponse.setHeader("Access-Control-Allow-Methods", 
                             "GET, POST, PUT, DELETE, OPTIONS");
        httpResponse.setHeader("Access-Control-Allow-Headers", 
                             "Content-Type, Authorization, X-Requested-With");
        httpResponse.setHeader("Access-Control-Max-Age", "3600");
        // 处理预检请求
        if ("OPTIONS".equalsIgnoreCase(httpRequest.getMethod())) {
            httpResponse.setStatus(HttpServletResponse.SC_OK);
            return;
        }
        chain.doFilter(request, response);
    }
}

5.5 XSS 防护过滤器

@WebFilter("/*")
public class XSSFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        // 包装请求对象,对参数进行 XSS 过滤
        XSSRequestWrapper wrappedRequest = new XSSRequestWrapper(
            (HttpServletRequest) request);
        chain.doFilter(wrappedRequest, response);
    }
}
// XSS 请求包装器
class XSSRequestWrapper extends HttpServletRequestWrapper {
    public XSSRequestWrapper(HttpServletRequest request) {
        super(request);
    }
    @Override
    public String getParameter(String name) {
        String value = super.getParameter(name);
        return cleanXSS(value);
    }
    @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;
    }
    @Override
    public String getHeader(String name) {
        String value = super.getHeader(name);
        return cleanXSS(value);
    }
    private String cleanXSS(String value) {
        if (value == null) return null;
        // 简单的 XSS 过滤
        return value.replaceAll("<", "<")
                   .replaceAll(">", ">")
                   .replaceAll("\"", "&quot;")
                   .replaceAll("'", "&#x27;")
                   .replaceAll("/", "&#x2F;")
                   .replaceAll("\\(", "&#40;")
                   .replaceAll("\\)", "&#41;")
                   .replaceAll("script", "scr_ipt")
                   .replaceAll("javascript", "java_script");
    }
}

6. Filter 的配置参数详解

6.1 URL 模式匹配

@WebFilter(
    urlPatterns = {
        "*.html",           // 所有 HTML 文件
        "/api/*",           // /api 路径下的所有请求
        "/admin/*",         // /admin 路径下的所有请求
        "/*"                // 所有请求
    }
)

6.2 Dispatcher 类型

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

6.3 初始化参数

@WebFilter(
    urlPatterns = "/*",
    initParams = {
        @WebInitParam(name = "excludePaths", value = "/static/,/public/"),
        @WebInitParam(name = "maxFileSize", value = "10485760"), // 10MB
        @WebInitParam(name = "allowedTypes", value = "jpg,png,pdf")
    }
)

7. Filter 的执行顺序

7.1 执行顺序规则

  1. web.xml 配置顺序:按照配置文件中定义的顺序执行
  2. 注解配置顺序:使用 @WebFilterfilterName 字母顺序
  3. 混合配置:web.xml 优先于注解

7.2 控制执行顺序的方法

// 方法1: 使用 web.xml 明确指定顺序
<filter-mapping>
    <filter-name>filter1</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>filter2</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
// 方法2: 使用 @Order 注解(需要框架支持)
@Order(1)
@WebFilter("/*")
public class FirstFilter implements Filter { }
@Order(2)
@WebFilter("/*")
public class SecondFilter implements Filter { }

8. Filter 的高级用法

8.1 条件过滤

@WebFilter("/*")
public class ConditionalFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String requestURI = httpRequest.getRequestURI();
        // 排除静态资源
        if (requestURI.startsWith("/static/") || 
            requestURI.endsWith(".css") || 
            requestURI.endsWith(".js")) {
            chain.doFilter(request, response);
            return;
        }
        // 对动态请求进行特殊处理
        System.out.printlnjs("处理动态请求: " + requestURI);
        // 添加自定义请求属性
        httpRequest.setAttribute("processingTime", System.currentTimeMillis());
        chain.doFilter(request, response);
        // 后处理
        Long startTime = (Long) httpRequest.getAttribute("processingTime");
        if (startTime != null) {
            long duration = System.currentTimeMillis() - startTime;
            System.out.println("请求处理耗时: " + duration + "ms");
        }
    }
}

8.2 响应包装器

@WebFilter("/*")
public class CompressionFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        String acceptEncoding = httpRequest.getHeader("Accept-Encoding");
        if (acceptEncoding != null && acceptEncoding.contains("gzip")) {
            // 使用 GZIP 压缩响应
            CompressionResponseWrapper wrappedResponse = 
                new CompressionResponseWrapper(httpResponse);
            chain.doFilter(request, wrappedResponse);
            // 完成压缩并发送响应
            wrappedResponse.finish();
        } else {
            chain.doFilter(request, response);
        }
    }
}
// 压缩响应包装器
class CompressionResponseWrapper extends HttpServletResponseWrapper {
    private GZIPServletOutputStream gzipStream;
    private PrintWriter printWriter;
    public CompressionResponseWrapper(HttpServletResponse response) 
        throws IOException {
        super(response);
    }
    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        if (printWriter != null) {
            throw new IllegalStateException("getWriter() has already been called");
        }
        if (gzipStream == null) {
            gzipStream = new GZIPServletOutputStream(super.getOutputStream());
        }
        return gzipStream;
    }
    @Override
    public PrintWriter getWriter() thphprows IOException {
        if (gzipStream != null) {
            throw new IllegalStateException("getOutputStream() has already been called");
        }
        if (printWriter == null) {
            gzipStream = new GZIPServletOutputStream(super.getOutputStream());
            printWriter = new PrintWriter(new OutputStreamWriter(gzipStream, 
                getCharacterEncoding()));
        }
        return printWriter;
    }
    public void finish() throws IOException {
        if (printWriter != null) {
            printWriter.close();
        }
        if (gzipStream != null) {
            gzipStream.finish();
        }
    }
}

9. Filter 的最佳实践

9.1 性能考虑

@WebFilter("/*")
public class PerformanceFilter implements Filter {
    private boolean enableProfiling;
    @Override
    public void init(FilterConfig filterConfig) {
        // 从配置中读取性能开关
        String profiling = filterConfig.getInitParameter("enableProfiling");
        this.enableProfiling = "true".equalsIgnoreCase(profiling);
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        if (!enableProfiling) {
            chain.doFilter(request, response);
            return;
        }
        long startTime = System.nanoTime();
        try {
     js       chain.doFilter(request, response);
        } finally {
            long endTime = System.nanoTime();
            long duration = (endTime - startTime) / 1_000_000; // 转换为毫秒
            if (duration > 1000) { // 超过1秒的记录警告
                System.err.println("慢请求: " + duration + "ms");
            }
        }
    }
}

9.2 异常处理

@WebFilter("/*")
public class ExceptionHandlingFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        try {
            chain.doFilter(request, response);
        } catch (Exception e) {
            // 统一异常处理
            handleException(e, request, response);
        }
    }
    private void handleException(Exception e, ServletRequest request, 
                               ServletResponse response) throws IOException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        // 记录异常日志
        System.err.println("处理请求时发生异常: " + httpRequest.getRequestURI());
        e.printStackTrace();
        // 返回统一的错误响应
        httpResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        httpResponse.setContentType("application/json");
        String errorJson = "{\"error\": \"服务器内部错误\", \"code\": 500}";
        httpResponse.getWriter().write(errorJson);
    }
}

10. Filter 的测试

10.1 单元测试示例

public class AuthenticationFilterTest {
    @Test
    public void testDoFilter_AuthenticatedUser() throws Exception {
        // 创建模拟对象
        HttpServletRequest mockRequest = mock(HttpServletRequest.class);
        HttpServletResponse mockResponse = mock(HttpServletResponse.class);
        FilterChain mockChain = mock(FilterChain.class);
        HttpSession mockSession = mock(HttpSession.class);
        // 设置模拟行为
        when(mockRequest.getSession(false)).thenReturn(mockSession);
        when(mockSession.getAttribute("user")).thenReturn(new User("testUser"));
        when(mockRequest.getRequestURI()).thenReturn("/user/profile");
        // 执行测试
        AuthenticationFilter filter = new AuthenticationFilter();
        filter.doFilter(mockRequest, mockResponse, mockChain);
        // 验证结果
        verify(mockChain).doFilter(mockRequest, mockResponse);
    }
    @Test
    public void testDoFilter_UnauthenticatedUser() throws Exception {
        // 创建模拟对象
        HttpServletRequest mockRequest = mock(HttpServletRequest.class);
        HttpServletResponse mockResponse = mock(HttpServletResponse.class);
        FilterChain mockChain = mock(FilterChain.class);
        // 设置模拟行为
        when(mockRequest.getSession(false)).thenReturn(null);
        when(mockRequest.getContextPath()).thenReturn("/myapp");
        // 执行测试
        AuthenticationFilter filter = new AuthenticationFilter();
        filter.doFilter(mockRequest, mockResponse, mockChain);
        // 验证重定向
        verify(mockResponse).sendRedirect("/myapp/login");
        verify(mockChain, never()).doFilter(mockRequest, mockResponse);
    }
}

总结

Filter 是 JavaWeb 中非常重要的组件,它提供了以下核心功能:

  1. 请求预处理响应后处理
  2. 链式处理机制
  3. 灵活的配置方式
  4. 强大的拦截能力

通过合理使用 Filter,可以实现:

  • 统一的字符编码处理
  • 身份认证和授权
  • 请求日志记录
  • 性能监控
  • 安全防护
  • 跨域处理
  • 数据压缩等

Filter 的设计遵循了 AOP(面向切面编程)的思想,使得横切关注点能够与业务逻辑分离,提高了代码的可维护性和复用性。

到此这篇关于JavaWeb 中的 Filter 详解的文章就介绍到这了,更多相关javaweb filter内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持China编程(www.chinasem.cn)!

这篇关于JavaWeb 中的 Filter组件详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1156296

相关文章

C++ move 的作用详解及陷阱最佳实践

《C++move的作用详解及陷阱最佳实践》文章详细介绍了C++中的`std::move`函数的作用,包括为什么需要它、它的本质、典型使用场景、以及一些常见陷阱和最佳实践,感兴趣的朋友跟随小编一起看... 目录C++ move 的作用详解一、一句话总结二、为什么需要 move?C++98/03 的痛点⚡C++

Java方法重载与重写之同名方法的双面魔法(最新整理)

《Java方法重载与重写之同名方法的双面魔法(最新整理)》文章介绍了Java中的方法重载Overloading和方法重写Overriding的区别联系,方法重载是指在同一个类中,允许存在多个方法名相同... 目录Java方法重载与重写:同名方法的双面魔法方法重载(Overloading):同门师兄弟的不同绝

MySQL中between and的基本用法、范围查询示例详解

《MySQL中betweenand的基本用法、范围查询示例详解》BETWEENAND操作符在MySQL中用于选择在两个值之间的数据,包括边界值,它支持数值和日期类型,示例展示了如何使用BETWEEN... 目录一、between and语法二、使用示例2.1、betwphpeen and数值查询2.2、be

python中的flask_sqlalchemy的使用及示例详解

《python中的flask_sqlalchemy的使用及示例详解》文章主要介绍了在使用SQLAlchemy创建模型实例时,通过元类动态创建实例的方式,并说明了如何在实例化时执行__init__方法,... 目录@orm.reconstructorSQLAlchemy的回滚关联其他模型数据库基本操作将数据添

Spring配置扩展之JavaConfig的使用小结

《Spring配置扩展之JavaConfig的使用小结》JavaConfig是Spring框架中基于纯Java代码的配置方式,用于替代传统的XML配置,通过注解(如@Bean)定义Spring容器的组... 目录JavaConfig 的概念什么是JavaConfig?为什么使用 JavaConfig?Jav

Java数组动态扩容的实现示例

《Java数组动态扩容的实现示例》本文主要介绍了Java数组动态扩容的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1 问题2 方法3 结语1 问题实现动态的给数组添加元素效果,实现对数组扩容,原始数组使用静态分配

Java中ArrayList与顺序表示例详解

《Java中ArrayList与顺序表示例详解》顺序表是在计算机内存中以数组的形式保存的线性表,是指用一组地址连续的存储单元依次存储数据元素的线性结构,:本文主要介绍Java中ArrayList与... 目录前言一、Java集合框架核心接口与分类ArrayList二、顺序表数据结构中的顺序表三、常用代码手动

JAVA项目swing转javafx语法规则以及示例代码

《JAVA项目swing转javafx语法规则以及示例代码》:本文主要介绍JAVA项目swing转javafx语法规则以及示例代码的相关资料,文中详细讲解了主类继承、窗口创建、布局管理、控件替换、... 目录最常用的“一行换一行”速查表(直接全局替换)实际转换示例(JFramejs → JavaFX)迁移建

Spring Boot Interceptor的原理、配置、顺序控制及与Filter的关键区别对比分析

《SpringBootInterceptor的原理、配置、顺序控制及与Filter的关键区别对比分析》本文主要介绍了SpringBoot中的拦截器(Interceptor)及其与过滤器(Filt... 目录前言一、核心功能二、拦截器的实现2.1 定义自定义拦截器2.2 注册拦截器三、多拦截器的执行顺序四、过

JAVA线程的周期及调度机制详解

《JAVA线程的周期及调度机制详解》Java线程的生命周期包括NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED,线程调度依赖操作系统,采用抢占... 目录Java线程的生命周期线程状态转换示例代码JAVA线程调度机制优先级设置示例注意事项JAVA线程