🐲 一文搞懂 【过滤器】 Filter

1、提出问题

2、三要素

①拦截

作为过滤器这样的组件,首先需要能够把请求拦截住,然后才能做后续的相关操作。

②过滤

通常是基于业务功能的需要,在拦截到请求之后编写特定的代码,对请求进行相关的处理或检查。

最典型的就是登录检查:检查当前请求是否已经登录。

③放行

如果当前请求满足过滤条件,那么就应该放行:让请求继续去找它原本要访问的资源。

3、HelloWorld

①创建Filter类

要求实现接口:jakarta.servlet.Filter。更简洁的做法是继承jakarta.servlet.http.HttpFilter类。

java 复制代码
/**  
 * 假设请求中携带一个特定的请求参数表示用户已经登录,可以访问私密资源。  
 * 特定请求参数名称:message,特定的值:monster  
 */public class Filter01HelloWorld extends HttpFilter {  
  
    @Override  
    public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {  
  
        // 1、获取请求参数  
        String message = request.getParameter("message");  
  
        // 2、检查请求参数是否满足预设的要求  
        if ("monster".equals(message)) {  
            // 3、满足条件的请求放行  
            chain.doFilter(request, response);  
        } else {  
            // 4、不满足预设条件就把请求转发到拒绝页面  
            request.getRequestDispatcher("/WEB-INF/pages/forbidden.html").forward(request, response);  
        }  
  
    }  
}

②注册Filter类

xml 复制代码
<!-- 注册 Filter --><filter>  
    <!-- Filter 友好名称 -->  
    <filter-name>Filter01HelloWorld</filter-name>  
  
    <!-- Filter 全类名 -->  
    <filter-class>com.filter.filter.Filter01HelloWorld</filter-class>  
</filter>  
<filter-mapping>  
    <!-- 引用 Filter 友好名称 -->  
    <filter-name>Filter01HelloWorld</filter-name>  
  
    <!-- 当前 Filter 要拦截的请求的 URL 地址的匹配模式 -->  
    <url-pattern>/private/*</url-pattern>  
</filter-mapping>

4、Filter生命周期

Servlet生命周期 Filter生命周期
创建对象 第一次接收到请求创建对象 通过反射调用无参构造器 执行一次 Web应用启动时创建对象 通过反射调用无参构造器 执行一次
初始化 创建对象之后立即执行 init()方法 执行一次 创建对象之后立即执行 init()方法 执行一次
干活 每一次接收到请求,处理请求 service()方法 可能多次 每一次接收到请求,过滤请求 doFilter()方法
销毁 Web应用卸载时执行 destroy()方法 执行一次 Web应用卸载时执行 destroy()方法 执行一次
java 复制代码
  
import jakarta.servlet.FilterChain;  
import jakarta.servlet.ServletException;  
import jakarta.servlet.http.HttpFilter;  
import jakarta.servlet.http.HttpServletRequest;  
import jakarta.servlet.http.HttpServletResponse;  
  
import java.io.IOException;  
  
public class Filter02LifeCycle extends HttpFilter {  
  
    // 生命周期相关:无参构造器  
    public Filter02LifeCycle() {  
        System.out.println("Filter02LifeCycle 执行了无参构造器!创建了对象!");  
    }  
  
    // 生命周期相关:初始化操作  
    @Override  
    public void init() throws ServletException {  
        System.out.println("Filter02LifeCycle 执行了init()方法,初始化完成!");  
    }  
  
    // 生命周期相关:清理或销毁操作  
    @Override  
    public void destroy() {  
        System.out.println("Filter02LifeCycle 执行了destroy()方法!");  
    }  
  
    // 生命周期相关:过滤请求操作  
    @Override  
    protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {  
        System.out.println("Filter02LifeCycle 执行了doFilter()方法!");  
        chain.doFilter(request, response);  
    }  
}
xml 复制代码
<filter>  
    <filter-name>Filter02LifeCycle</filter-name>  
    <filter-class>com.filter.filter.Filter02LifeCycle</filter-class>  
</filter>  
<filter-mapping>  
    <filter-name>Filter02LifeCycle</filter-name>  
    <!-- 拦截当前 Web 应用下的所有资源 -->  
    <url-pattern>/*</url-pattern>  
</filter-mapping>

5、Filter链

①Filter链的形成

当多个Filter拦截同一个资源,那么访问这个资源的请求就需要逐个经过各个Filter。

②Filter链的执行

  • 每个Filter都放行,请求才能到达原本要访问的目标资源
  • 有任何一个Filter没有放行,那么后面的Filter和目标资源就都不会被执行
  • Filter如果没有放行,那么需要给出响应。例如:转发、重定向等方式。
  • Filter如果没有放行,也没有给出响应,那么浏览器窗口就是一片空白。

③Filter链执行的顺序

参考web.xml中filter-mapping的顺序:

  • filter-mapping靠前的:Filter执行时在外层(先执行:先开始,后结束)
  • filter-mapping靠后的:Filter执行时在内层(后执行:后开始,先结束)

本质上来说,同一个Filter链中的各个方法都是在同一个线程里依次调用的方法:

④引申

  • 方法栈:同一个线程内,先调用的方法后结束;后调用的方法先结束

  • 同一个线程内,所有操作本质上都是按顺序执行的。前面操作没有执行完,后面操作就需要等待。

  • 在不同线程(或进程)内,各个操作都不需要等待其它线程中操作的执行。

  • 同步:操作之间需要彼此等待,按顺序依次执行

  • 异步:操作之间不需要彼此等待,同时各自执行

6、登录检查练习

①需求说明

凡是对Soldier增删改查操作,都需要登录才能访问

②创建Filter类

java 复制代码
import com.demo.entity.User;  
import jakarta.servlet.FilterChain;  
import jakarta.servlet.ServletException;  
import jakarta.servlet.http.HttpFilter;  
import jakarta.servlet.http.HttpServletRequest;  
import jakarta.servlet.http.HttpServletResponse;  
import jakarta.servlet.http.HttpSession;  
  
import java.io.IOException;  
  
public class LoginFilter extends HttpFilter {  
  
    @Override  
    protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {  
        HttpSession session = request.getSession();  
        User loginUser = (User) session.getAttribute("loginUser");  
        if (loginUser == null) {  
            request.setAttribute("message", "请登录后再操作!");  
            request.getRequestDispatcher("/UserServlet/toLoginPage").forward(request, response);  
        } else {  
            chain.doFilter(request, response);  
        }  
    }  
}

③注册Filter类

xml 复制代码
<filter>  
    <filter-name>loginFilter</filter-name>  
    <filter-class>com.demo.filter.LoginFilter</filter-class>  
</filter>  
<filter-mapping>  
    <filter-name>loginFilter</filter-name>  
    <url-pattern>/SoldierServlet/*</url-pattern>  
</filter-mapping>
相关推荐
_oP_i1 小时前
Pinpoint 是一个开源的分布式追踪系统
java·分布式·开源
mmsx1 小时前
android sqlite 数据库简单封装示例(java)
android·java·数据库
武子康1 小时前
大数据-258 离线数仓 - Griffin架构 配置安装 Livy 架构设计 解压配置 Hadoop Hive
java·大数据·数据仓库·hive·hadoop·架构
豪宇刘2 小时前
MyBatis的面试题以及详细解答二
java·servlet·tomcat
秋恬意2 小时前
Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别
java·数据库·mybatis
刘大辉在路上3 小时前
突发!!!GitLab停止为中国大陆、港澳地区提供服务,60天内需迁移账号否则将被删除
git·后端·gitlab·版本管理·源代码管理
FF在路上3 小时前
Knife4j调试实体类传参扁平化模式修改:default-flat-param-object: true
java·开发语言
真的很上进3 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
众拾达人4 小时前
Android自动化测试实战 Java篇 主流工具 框架 脚本
android·java·开发语言
皓木.4 小时前
Mybatis-Plus
java·开发语言