当前位置: 首页 > article >正文

Java Web-Filter

Filter

在 Java Web 开发中,Filter(过滤器)是 Servlet 规范中的一个重要组件,它可以对客户端与服务器之间的请求和响应进行预处理和后处理。以下从多个方面详细介绍 Java Web 中的 Filter:

一、概念和作用

  • 概念:Filter 是一种特殊的 Servlet 组件,它可以在请求到达目标资源(如 Servlet、JSP 等)之前或响应返回客户端之前对请求和响应进行拦截和处理。
  • 作用
    • 权限验证:检查用户是否具有访问某个资源的权限,例如在用户未登录时阻止其访问需要登录才能访问的页面。
    • 字符编码处理:统一设置请求和响应的字符编码,避免出现乱码问题。
    • 日志记录:记录每个请求的详细信息,如请求的 URL、参数、请求时间等,方便后续的系统监控和问题排查。
    • 数据过滤和验证:对请求参数进行过滤和验证,防止恶意输入或不符合要求的数据进入系统。

二、工作原理

当客户端发送请求到服务器时,请求首先会经过一系列的 Filter。每个 Filter 可以对请求进行检查和修改,然后将请求传递给下一个 Filter 或目标资源。当目标资源处理完请求后,响应会按照相反的顺序再次经过这些 Filter,每个 Filter 可以对响应进行后处理,最后将响应返回给客户端。

实现步骤

1. 创建 Filter 类

Filter 类需要实现 javax.servlet.Filter 接口,并重写其中的三个方法:init()doFilter() 和 destroy()

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

public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化方法,在 Filter 实例创建后调用,可用于初始化资源
        System.out.println("MyFilter 初始化");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // 过滤方法,对请求和响应进行处理
        System.out.println("MyFilter 开始处理请求");
        // 设置请求和响应的字符编码
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        // 将请求和响应传递给下一个 Filter 或目标资源
        chain.doFilter(request, response);
        System.out.println("MyFilter 处理响应结束");
    }

    @Override
    public void destroy() {
        // 销毁方法,在 Filter 实例销毁前调用,可用于释放资源
        System.out.println("MyFilter 销毁");
    }
}
2. 配置 Filter

有两种常见的配置方式:使用 web.xml 配置文件或使用注解。

使用 web.xml 配置

<filter>
    <filter-name>MyFilter</filter-name>
    <filter-class>com.example.MyFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>MyFilter</filter-name>
    <!-- 过滤所有请求 -->
    <url-pattern>/*</url-pattern>
</filter-mapping>

用注解配置

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

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

三、Filter 链

在 Java Web 开发中,过滤器链(Filter Chain)是一个重要的概念,它允许多个过滤器(Filter)按照特定顺序对请求和响应进行处理。下面将从过滤器链的概念、工作原理、配置方式、执行顺序以及应用场景等方面进行详细解释。

概念

过滤器链是由多个过滤器组成的一个有序列表。当客户端向服务器发送请求时,请求会依次经过过滤器链中的每个过滤器,每个过滤器可以对请求进行预处理,如验证用户身份、设置字符编码等。当请求到达目标资源(如 Servlet、JSP 等)并处理完成后,响应会按照相反的顺序再次经过过滤器链,每个过滤器可以对响应进行后处理,如压缩响应数据、添加响应头信息等。

工作原理

  1. 请求阶段:客户端发送请求到服务器,服务器接收到请求后,会根据配置的过滤器链,依次将请求传递给链中的每个过滤器。每个过滤器在接收到请求后,可以对请求进行修改或增强,然后将请求传递给下一个过滤器。如果某个过滤器决定不将请求继续传递给下一个过滤器,它可以直接返回响应给客户端,从而终止请求的处理流程。
  2. 响应阶段:当请求到达目标资源并处理完成后,服务器会生成响应。响应会按照与请求阶段相反的顺序经过过滤器链,每个过滤器可以对响应进行修改或增强,最后将响应返回给客户端。

配置方式

可以通过 web.xml 配置文件或注解的方式来配置过滤器链。

使用 web.xml 配置
<filter>
    <filter-name>Filter1</filter-name>
    <filter-class>com.example.Filter1</filter-class>
</filter>
<filter>
    <filter-name>Filter2</filter-name>
    <filter-class>com.example.Filter2</filter-class>
</filter>
<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>

在上述配置中,Filter1 和 Filter2 会组成一个过滤器链,请求会先经过 Filter1,再经过 Filter2

使用注解配置
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter(urlPatterns = "/*", filterName = "Filter1")
public class Filter1 implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // 预处理逻辑
        System.out.println("Filter1: 请求预处理");
        chain.doFilter(request, response);
        // 后处理逻辑
        System.out.println("Filter1: 响应后处理");
    }
}

@WebFilter(urlPatterns = "/*", filterName = "Filter2")
public class Filter2 implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // 预处理逻辑
        System.out.println("Filter2: 请求预处理");
        chain.doFilter(request, response);
        // 后处理逻辑
        System.out.println("Filter2: 响应后处理");
    }
}

在上述代码中,Filter1 和 Filter2 都会对所有请求进行拦截,具体的执行顺序可能因 Servlet 容器而异。

执行顺序

  • web.xml 配置:在 web.xml 中,<filter-mapping> 标签的配置顺序决定了过滤器的执行顺序。先配置的过滤器会先执行,后配置的过滤器后执行。
  • 注解配置:使用注解配置时,不同的 Servlet 容器可能有不同的处理方式。有些容器会按照类名的字典序来决定过滤器的执行顺序,而有些容器可能没有明确的顺序。为了确保过滤器按照预期的顺序执行,建议使用 web.xml 进行配置。

应用场景

  • 身份验证和授权:可以使用多个过滤器来实现不同级别的身份验证和授权。例如,一个过滤器用于验证用户是否已登录,另一个过滤器用于验证用户是否具有访问特定资源的权限。
  • 字符编码处理:可以在过滤器链中配置一个过滤器,用于统一设置请求和响应的字符编码,避免出现乱码问题。
  • 日志记录:可以使用过滤器链来记录每个请求的详细信息,如请求的 URL、参数、请求时间等,方便后续的系统监控和问题排查。
  • 数据过滤和验证:可以在过滤器链中配置多个过滤器,对请求参数进行过滤和验证,防止恶意输入或不符合要求的数据进入系统。

示例代码执行结果分析

假设有上述的 Filter1 和 Filter2 两个过滤器,当客户端发送一个请求时,控制台可能会输出以下信息:

Filter1: 请求预处理
Filter2: 请求预处理
(目标资源处理请求)
Filter2: 响应后处理
Filter1: 响应后处理

从输出结果可以看出,请求阶段过滤器按照 Filter1 -> Filter2 的顺序执行,响应阶段过滤器按照 Filter2 -> Filter1 的顺序执行。

通过使用过滤器链,可以将不同的功能逻辑分离到不同的过滤器中,提高代码的可维护性和可扩展性。

四、应用场景举例

登录验证 Filter
package com.itheima.web.filter;

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

@WebFilter("/*")
public class LoginFilter implements Filter {
    // 未登录即可放行的资源列表,常量
    private static final String[] PUBLIC_URLS = {
           "/adminServlet","index.html", "admin.jsp", "register.jsp", "/registerServlet", "login.jsp", "/loginServlet"
    };

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        // 设置请求和响应的字符编码,避免中文乱码
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        HttpServletRequest req = (HttpServletRequest) request;
        // 获取请求的 URI 部分
        String uri = req.getRequestURI();

        // 检查是否为未登录即可放行的资源
        for (String u : PUBLIC_URLS) {
            if (uri.endsWith(u)) {
                // 可以放行
                chain.doFilter(request, response);
                return;
            }
        }

        // 到这步说明访问的资源不可以直接放行,必须登录
        HttpSession session = req.getSession();
        Object user = session.getAttribute("user");
        Object admin = session.getAttribute("admin");

        // 判断 user 或 admin 是否不为 null
        if (user != null || admin != null) {
            // 用户或管理员已登录,放行请求
            chain.doFilter(request, response);
        } else {
            // 没登陆过,跳转到登录页面
            req.setAttribute("login_errmsg", "请登录");
            req.getRequestDispatcher("login.jsp").forward(request, response);
        }
    }

    @Override
    public void destroy() {
    }
}

这个 Filter 会检查用户是否已登录,如果未登录则重定向到登录页面。


http://www.kler.cn/a/573297.html

相关文章:

  • 面试基础---MySQL 事务隔离级别与 MVCC 深度解析
  • IP地址怎么加密https访问?
  • JAVA毕设项目-基于SSM框架的百色学院创新实践学分认定系统源码+设计文档
  • 毕业项目推荐:基于yolov8/yolov5/yolo11的田间杂草检测识别系统(python+卷积神经网络)
  • Stable Diffusion LoRA 技术详解
  • debian/control 文件中的${misc:Depends}
  • 如何在React中正确处理异步操作?
  • windows 利用nvm 管理node.js 2025最新版
  • 靶场之路-VulnHub-DC-6 nmap提权、kali爆破、shell反连
  • DAViMNet:基于状态空间模型的域自适应目标检测
  • 二、Java-封装playwright UI自动化(根据官网执行步骤,首先封装BrowserFactory枚举类及BrowserManager)
  • Python开发高效PDF批量转Word
  • 前端基础之内置指令与自定义指令
  • VsCode 快捷键备忘
  • CentOS 7 安装Nginx-1.26.3
  • 【3】VS Code 新建上位机项目---C#窗体与控件开发
  • 海康机器人搞工业机器人,我以为它忘记自己名字,作为技术,作为业务你跟不跟,机器视觉工程师搞视觉引导必须知道工业机器人四大坐标系
  • 前端开发10大框架深度解析
  • 【单片机】嵌入式系统设计流程
  • JavaWeb-HttpServletRequest请求域接口