JavaWeb 中 Filter过滤器

这篇具有很好参考价值的文章主要介绍了JavaWeb 中 Filter过滤器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Filter过滤器

JavaWeb 中 Filter过滤器

每博一文案

师傅说:人生无坦途,累是必须的背负,看多了,人情人暖,走遍了离合聚散,有时会
在心里对自己说,我想,我是真的累了,小时候有读不完的书,长大后有赚不尽的力。
白天在外要奋斗打拼,把心事都藏起来,笑脸相迎,做一个合格的员工,晚上回家要照顾家人。
把家务都打理的井井有条,做一个称职的伴侣,习惯了所有事情,自己扛,习惯了所有委屈自己消化,
有时候莫名的低落,什么话都不想说,只想一个静静的发呆,有时会突然的烦躁,什么事都不想做,
只想让自己好好的放松,偶尔也会向往过一份属于自己的生活。
没有那么多责任,要背负只做自己想做的事,累了就停下类休息吧,烦了就给自己放个假吧。
这个世上没有铁打的身体,该休息时就得休息。
这个世上没有坚强的心灵,该哭泣时就该哭泣。
看看碧海蓝天,听听轻歌曼舞,会会知己老友,品品清茶,美酒,生活本就可以多姿多彩。
人生说到底,活的是心气,为累过,方知闲,为苦过,方知甜,随缘自在,勿忘心安,便是活着的最美状态。
                                       ——————《一禅心灵庙语1》

@

目录
  • Filter过滤器
    • 每博一文案
    • 1. Filter 过滤器的概述
    • 2. Filter 过滤器的编写
    • 3. Filter 过滤器的执行过程解析
      • 3.1 Filter 过滤结合 Servlet 的使用
    • 4. Filter 过滤器的拦截路径:
      • 4.1 精确匹配路径
      • 4.2 目录匹配
      • 4.3 前后缀名路径匹配
      • 4.4 所有路径匹配
    • 5. 设置 Filter 执行顺序
    • 6. Filter 过滤器中的责任链设计模式思想
    • 7. 运用 Filter 过滤器的方式优化 oa 项目的一个登录验证:
    • 8. 总结:
    • 9. 最后:

1. Filter 过滤器的概述

JavaWeb 中 Filter过滤器

在一个比较复杂的Web应用程序中,通常都有很多URL映射,对应的,也会有多个Servlet来处理URL。

我们考察这样一个论坛应用程序:

            ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
               /             ┌──────────────┐
            │ ┌─────────────>│ IndexServlet │ │
              │              └──────────────┘
            │ │/signin       ┌──────────────┐ │
              ├─────────────>│SignInServlet │
            │ │              └──────────────┘ │
              │/signout      ┌──────────────┐
┌───────┐   │ ├─────────────>│SignOutServlet│ │
│Browser├─────┤              └──────────────┘
└───────┘   │ │/user/profile ┌──────────────┐ │
              ├─────────────>│ProfileServlet│
            │ │              └──────────────┘ │
              │/user/post    ┌──────────────┐
            │ ├─────────────>│ PostServlet  │ │
              │              └──────────────┘
            │ │/user/reply   ┌──────────────┐ │
              └─────────────>│ ReplyServlet │
            │                └──────────────┘ │
             ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─

各个Servlet设计功能如下:

  • IndexServlet:浏览帖子;
  • SignInServlet:登录;
  • SignOutServlet:登出;
  • ProfileServlet:修改用户资料;
  • PostServlet:发帖;
  • ReplyServlet:回复。

其中,ProfileServlet、PostServlet和ReplyServlet都需要用户登录后才能操作,否则,应当直接跳转到登录页面。

我们可以直接把判断登录的逻辑写到这3个Servlet中,但是,同样的逻辑重复3次没有必要,并且,如果后续继续加Servlet并且也需要验证登录时,还需要继续重复这个检查逻辑。

为了把一些公用逻辑从各个Servlet中抽离出来,JavaEE的Servlet规范还提供了一种Filter组件,即过滤器,它的作用是,在HTTP请求到达Servlet之前,可以被一个或多个Filter预处理,类似打印日志、登录检查等逻辑,完全可以放到Filter中。

JavaWeb 中 Filter过滤器

JavaWeb 中 Filter过滤器

JavaWeb 中 Filter过滤器

什么是 Filter 过滤器:

  1. Filter 过滤器它是 JavaWeb 的三大组件之一。
    三大组件分别是:Servlet 程序、Listener 监听器、Filter 过滤器
  2. Filter 过滤器它是 JavaEE 的规范。也就是接口
  3. Filter 过滤器它的作用是:拦截请求,过滤响应。

拦截请求常见的应用场景有:
1.权限检查 2.日记操作 3.事务管理 ……等等

一般情况下,都是在过滤器当中编写公共代码。提高代码的复用性.

2. Filter 过滤器的编写

  • 第一步:编写一个Java类实现一个接口:jarkata.servlet.Filter。并且实现这个接口当中所有的方法。

JavaWeb 中 Filter过滤器

JavaWeb 中 Filter过滤器

JavaWeb 中 Filter过滤器

  • init( )方法:在Filter对象第一次被创建之后调用,并且只调用一次。与Servlet中的init()方法类似,filter中的init()方法用于初始化过滤器。开发者可以在init()方法中完成与构造方法类似的初始化功能。如果初始化代码中要用到FilterConfig对象,则这些初始化代码只能在filter的init()方法中编写,而不能在构造方法中编写。 default 是接口中的一个默认方法,基于 jdk8 新特性,默认方法可以不用重写,如果有需要也是可以重写的.
public default void init(FilterConfig filterConfig) throws ServletException {}
  • doFilter( )方法:只要用户发送一次请求,则执行一次。发送N次请求,则执行N次。在这个方法中编写过滤规则。需要注意的是,服务器响应的时候,该方法也是会被执行的。doFilter方法类似于Servlet接口的service()方法。当客户端请求目标资源时,容器会筛选出符合<filter-mapping>标签中<url-pattern>的filter,并按照声明<filter-mapping>的顺序依次调用这些filter的doFilter()方法。doFilter()方法有多个参数,其中参数requestresponse为Web服务器或filter链中的上一个filter传递过来的请求和响应对象。参数chain代表当前filter链的对象,只有当前filter对象中的doFilter()方法内部需要调用FilterChain对象的doFilter方法时,才能把请求交付给filter链中的下一个filter或目标程序处理。这个是抽象方法,必须重写。
 public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException;
  • destroy( )方法:在Filter对象被释放/销毁之前调用,并且只调用一次。 filter中的destroy()方法Servlet中的destroy()作用类似,在Web服务器卸载filter对象之前被调用,用于释放被filter对象打开的资源。 default 是接口中的一个默认方法,基于 jdk8 新特性,默认方法可以不用重写,如果有需要也是可以重写的.
 public default void destroy() {}
package com.RainbowSea.filter;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;

import java.io.IOException;

public class TestFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("TestFilter 中的 init() 方法 初始化 执行了");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("TestFilter 中的 doFilter() 方法执行了");
    }

    @Override
    public void destroy() {
        System.out.println("TestFilter 中的 destroy() 方法 销毁 执行了");
    }
}

  • 第二步:在web.xml文件中对 Filter进行配置。这个配置和 Servlet很像。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
         version="5.0">

    <filter>
        <!--        两个 name 名是要保持一致的-->
        <filter-name>filter</filter-name>
        <!--        对应的全类路径名,全类限定名-->
        <filter-class>com.RainbowSea.filter.TestFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>filter</filter-name>
        <!--        Filter 的映射路径,以 / 开始-->
        <url-pattern>/a.do</url-pattern>
    </filter-mapping>
    
    
</web-app>

如下是关于: Filter的所有的 web.xml 中的配置属性信息:

标签 作用
<filter> 指定一个过滤器
<filter-name> 用于为过滤器指定一个名称,该元素的内容不能为空
<filter-class> 用于指定过滤器的完整的限定类名
<init-param> 用于为过滤器指定初始化参数
<param-value> <init-param>的子参数,用于指定参数的名称
<filter-mapping> 用于设置一个filter所负责拦截的资源
<filter-name> <filter-mapping>子元素,用于设置filter的注册名称。该值必须是在<filter>元素中声明过的过滤器的名称
<url-pattern> 用于设置filter所拦截的请求路径
<servlet-name> 用于指定过滤器所拦截的Servlet名称

执行效果:

JavaWeb 中 Filter过滤器

JavaWeb 中 Filter过滤器

JavaWeb 中 Filter过滤器

如果Servlet版本大于3.0,也可以使用注解 @WebFilter()的方式来配置filter。

JavaWeb 中 Filter过滤器

如下:

package com.RainbowSea.filter;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;

import java.io.IOException;


@WebFilter("/a.do")
public class TestFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("TestFilter 中的 init() 方法 初始化 执行了");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("TestFilter 中的 doFilter() 方法执行了");
    }

    @Override
    public void destroy() {
        System.out.println("TestFilter 中的 destroy() 方法 销毁 执行了");
    }
}

如下是关于:@WebFilter() 的属性的说明:

属性 类型 是否必须 说明
asyncSupported boolean 指定filter是否支持异步模式
dispatcherTypes DispatcherType[] 指定filter对哪种方式的请求进行过滤
filterName String filter名称
initParams WebInitParam[] 配置参数
displayName String filter显示名
servletNames String[] 指定对哪些Servlet进行过滤
urlPatterns/value String[] 两个属性作用相同,指定拦截的路径

web.xml可以配置的filter属性都可以通过@WebServlet的方式进行配置。不过一般不推荐使用注解方式来配置filter,因为如果存在多个过滤器,使用web.xml配置filter可以控制过滤器的执行顺序,如果使用了注解方式,则不可以这样做了。该 Filter 执行顺序该文章的后面会详细说明,所以请大家,耐心阅读。谢谢。

3. Filter 过滤器的执行过程解析

JavaWeb 中 Filter过滤器

JavaWeb 中 Filter过滤器

JavaWeb 中 Filter过滤器

当用户向服务器发送request请求时,服务器接受该请求,并将请求发送到第一个过滤器中进行处理。如果有多个过滤器,则会依次经过filter2,filter3,…,filter n。接着调用Servlet中的service()方法,调用完毕后,按照与进入时相反的顺序,从过滤器filter n开始,依次经过各个过滤器,直到过滤器filter 1.最终将处理后的结果返回给服务器,服务器再反馈给用户。

filter进行拦截的方式也很简单,在HttpServletRequest到达Servlet之前,filter拦截客户的HttpServletRequest,根据需要检查HttpServletRequest,也可以修改HttpServletRequest头和数据。在HttpServletRequest到达客户端之前,拦截HttpServletRequest,根据需要检查HttpServletRequest,也可以修改HttpServletResponse头和数据。

3.1 Filter 过滤结合 Servlet 的使用

想要让 Filter 可以过滤用户对 Servlet 发送的请求,必须满足如下两个条件:

  • 第一个:在 Filter 过滤器当中的 doFilter() 方法中编写:chain.doFilter(request, response) 方法:该方法的作用是:执行下一个过滤器,如果下面没有过滤器了(Filter 过滤器之间的 映射路径是相同的情况下),执行最终的Servlet(在Servlet 与 Filter 过滤器的映射路径是相同的情况下。)
@Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 执行下一个过滤器,如果下面没有过滤器了,执行最终的Servlet
        chain.doFilter(request,response);
    } 
  • 第二:用户发送的请求路径是否和Servlet的请求路径一致。而 Filter过滤器的映射路径是否包含/和Servlet的请求路径一致。只有 Filter 过滤器映射路径包含/和 Servlet 的请求映射路径是一致的,Filter才会过滤该用户方法的请求信息。
  • 注意:Filter的优先级,天生的就比Servlet优先级高。:比如:/a.do 对应一个Filter,也对应一个Servlet。那么一定是先执行Filter,然后再执行Servlet。

举例:

JavaWeb 中 Filter过滤器

package com.RainbowSea.filter;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;

import java.io.IOException;


@WebFilter("/a.do")
public class TestFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("TestFilter 中的 doFilter() 方法 begin 开始执行了");

        // 表示:执行下一个 Filter(同一个 映射的路径,如果有下一个Filter 的话),没有就执行(同一个映射的路径的 Servlet )
        chain.doFilter(request,response);

        System.out.println("TestFilter 中的 doFilter() 方法 end 执行结束");
    }

}

package com.RainbowSea.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;


@WebServlet("/a.do")
public class AServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
            IOException {
        System.out.println("AServlet 执行了");
    }
}

测试效果:

JavaWeb 中 Filter过滤器

JavaWeb 中 Filter过滤器

JavaWeb 中 Filter过滤器

案例举例:

LoginFilter 过滤器,获取到客户端发送过来的请求,进行一个过滤,判断用户的账号和密码是否正确,正确的话,LoginFilter 过滤器放行,到 LogServlet 表示登录成功。如果用户的账号和密码是错误的,则让提示用户密码错误,请重新登录。

这里为了方便演示核心,我们就将 账号和密码写死了,账号为: admin ,密码为 123

package com.RainbowSea.filter;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;


@WebFilter("/login")
public class LoginFilter implements Filter {
    @Override
    public void doFilter(ServletRequest requ, ServletResponse resp, FilterChain chain) throws IOException,
            ServletException {


        HttpServletRequest request = (HttpServletRequest) requ;
        HttpServletResponse  response= (HttpServletResponse) resp;

        request.setCharacterEncoding("UTF-8");  // 设置获取到的请求信息的字符编码:

        // 获取到用户的请求信息

        String name = request.getParameter("user");
        String password = request.getParameter("password");


        // 过滤器:判断用户登录的账号和密码是否正确
        if ("admin".equals(name) && "123".equals(password)) {
            // 正确:放行
            // 表示:执行下一个 Filter(同一个 映射的路径,如果有下一个Filter 的话),没有就执行(同一个映射的路径的 Servlet )
            chain.doFilter(request,response);

        } else {
            // 跳转至登录失败的页面
            response.sendRedirect(request.getContextPath()+"/error.jsp");
        }
    }
}

package com.RainbowSea.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;


@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charSet=utf-8");

        PrintWriter writer = response.getWriter();

        writer.println("登录成功");
    }
}


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<h3>登录失败,请重新登录</h3>

</body>
</html>

JavaWeb 中 Filter过滤器

JavaWeb 中 Filter过滤器

Filter 过滤器的生命周期

JavaWeb 中 Filter过滤器

当Web容器启动时,会根据web.xml中声明的filter顺序依次实例化这些filter。然后在Web应用程序加载时调用init()方法,随机客户端有请求时调用doFilter()方法,并且根据实际情况的不同,doFilter()方法可能被调用多次。最后Web应用程序卸载时调用destroy()方法。

Filter 过滤器与 Servlet 的区别:

  • servlet对象默认情况下,在服务器启动的时候是不会新建对象的。
  • Filter对象默认情况下,在服务器启动的时候会新建对象。
  • Servlet是单例的。Filter也是单例的。(单实例,但是它们都是假单例,因为真单例的构造器是 private 的,而这两个类都不是私有的构造器)
  • Filter 和Servlet对象生命周期一致。
  • 唯一的区别:Filter默认情况下,在服务器启动阶段就实例化。Servlet不会。
  • Filter的优先级,天生的就比Servlet优先级高。比如:/a.do 对应一个Filter,也对应一个Servlet。那么一定是先执行Filter,然后再执行Servlet。

4. Filter 过滤器的拦截路径:

关于Filter的配置路径:不同的 Filter 映射路径,所拦截用户请求的也是不一样的。

关于 Filter 过滤器路径的配置:大致可以分别如下四种:

  • 精确匹配路径:/a.do、/b.do、/dept/save。这些配置方式都是精确匹配。

  • 目录匹配:/admin/*

  • 匹配所有路径: /*
  • 前后缀名路径匹配:后缀:*.do 后缀匹配。不要以 / 开始,前缀:/dept/* 前缀匹配。

4.1 精确匹配路径

只有完美匹配,一个符号,一个字符,不能错误的路径。Filter 只会过滤用户访问该:/target/dep路径的信息才会拦截判断是否放行。其他用户访问的路径一概不会进行 Filter 过滤器过滤

<filter-mapping>
    <filter-name>Filter</filter-name>
    <url-pattern>/target/dep</url-pattern>  <!--精确匹配-->
</filter-mapping>

4.2 目录匹配

Filter 会过滤用户访问该:/admin/* admin子路径包含 admin路径的信息:比如:/admin/test/admin/test/test2才会拦截判断是否放行。其他用户访问的路径一概不会进行 Filter 过滤器过滤。

<filter-mapping>
    <filter-name>Filter</filter-name>
    <url-pattern>/admin/*</url-pattern> <!--目录匹配-->
</filter-mapping>

4.3 前后缀名路径匹配

后缀路径匹配:以上配置的路径,表示请求地址必须以.do 结尾才会被 Filter 过滤器拦截判断是否放行。

注意的是:不要以 / 开始 ,不然就失效了。

<filter-mapping>
    <filter-name>Filter</filter-name>
    <url-pattern>*.do</url-pattern> <!--目录匹配-->
</filter-mapping>

前缀路径匹配:以上配置的路径,表示请求地址必须以/admin/ 开头才会被 Filter 过滤器拦截判断是否放行

<filter-mapping>
    <filter-name>Filter</filter-name>
    <url-pattern>/admin/*</url-pattern> <!--目录匹配-->
</filter-mapping>

4.4 所有路径匹配

/* 表示对应任何请求地址,Filter 过滤器都会进行一个拦截判断是否放行,那么这个路径的资源不存在也会,进行一个拦截判断是否放行。这种方式虽然简单,但是,这个代价比较到,效率低,对于特殊的路径请求要放行的你可能需要编写大量的逻辑判断进行一个拦截放行。不建议使用。

<filter-mapping>
    <filter-name>Filter</filter-name>
    <url-pattern>/*</url-pattern> <!--目录匹配-->
</filter-mapping>

5. 设置 Filter 执行顺序

一个 Servelt 是可以设置多个 Filter 过滤器的,当我们设置了多个 Filter 过滤器,其中 Filter 过滤器的执行顺序该如何设置呢?

从上面文章的内容,我们知道了 Filter 的映射路径设置有两种方式:

  1. 注解:@WebFilter()
  2. 配置 web.xml 文件的方式。这种方式 推荐使用

两种设置 Filter的方式不同,对于设置的执行顺序的方式也是不一样的。

对于 Filter 执行顺序的设置,虽然有两种方式,但是推荐使用 web.xml 配置文件的方式,因为使用 注解@WebFilter() 的方式的话,我们需要更加定义的类名的字母顺序的方式来,设置Filter的执行顺序,这样会改变一个类名的见名之意。而如果是使用 web.xml 配置文件的方式,直接更加 Filtet 编写的配置是先后顺序就可以了。

过滤器的调用顺序,遵循栈数据结构。

第一种:注解的方式:设置Filter过滤器的执行顺序:

注解的方式:

执行顺序是:比较 Filter 这个类名。就是你定义的这个类名 implements (实现) Filter 的类名

JavaWeb 中 Filter过滤器

  • 比如:FilterA和FilterB,则先执行FilterA
  • 比如:Filter1和Filter2,则先执行Filter1

举例验证:

JavaWeb 中 Filter过滤器

JavaWeb 中 Filter过滤器

JavaWeb 中 Filter过滤器

JavaWeb 中 Filter过滤器

通过:配置 web.xml 文件的方式,如何设置 Filter 的执行顺序:

web.xml 中是:依靠 <filter-mapping>标签的配置位置,越靠上优先级越高,就越先执行其中的 Filter的 doFilter() 方法。

举例证实:

JavaWeb 中 Filter过滤器

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
         version="5.0">

    <filter>
        <filter-name>FilterB</filter-name>
        <filter-class>com.RainbowSea.filter.FilterB</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>FilterB</filter-name>
        <url-pattern>/A</url-pattern>
    </filter-mapping>

    <filter>
        <!--        两个 name 名是要保持一致的-->
        <filter-name>FilterA</filter-name>
        <!--        对应的全类路径名,全类限定名-->
        <filter-class>com.RainbowSea.filter.FilterA</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>FilterA</filter-name>
        <!--        Filter 的映射路径,以 / 开始-->
        <url-pattern>/A</url-pattern>
    </filter-mapping>




</web-app>
package com.RainbowSea.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;


@WebServlet("/A")
public class AServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException,
            IOException {
        System.out.println("AServlet doGet()  执行了");


    }
}

package com.RainbowSea.filter;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;


import java.io.IOException;



public class FilterB implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        System.out.println("FilterB doFilter() 执行了");

        // 表示执行后面的(映射路径相同的Filter 过滤器),如果后面没有的话执行(映射路径相同的 Servlet)
        chain.doFilter(request,response);

    }
}

package com.RainbowSea.filter;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;


import java.io.IOException;




public class FilterA implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("FilterA  doFilter() 执行了");

        // 表示执行后面的(映射路径相同的Filter 过滤器),如果后面没有的话执行(映射路径相同的 Servlet)
        chain.doFilter(request,response);
    }
}

JavaWeb 中 Filter过滤器

6. Filter 过滤器中的责任链设计模式思想

23种设计模式 : 责任链设计模式

过滤器最大的优点:

在程序编译阶段不会确定调用顺序。因为Filter的调用顺序是配置到web.xml文件中的,只要修改web.xml配置文件中filter-mapping的顺序就可以调整Filter的执行顺序。显然Filter的执行顺序是在程序运行阶段动态组合的。那么这种设计模式被称为责任链设计模式。

责任链设计模式最大的核心思想:在程序运行阶段,动态的组合程序的调用顺序。在上面对于 Filter的使用当中,我们已经体验到了,Filter 的动态调用其中的 doFilter() 方法,通过修改其中的 web.xml 对 Filter 的配置顺序。

下面我们演示一下不是 :责任链设计模式的方式:

如下这种方式:是我们写死了的,想要改变其中的执行顺序,就必须通过修改其中的源码当中的,代码的执行顺序,无法通过通过配置文件的方式,修改调用的顺序。

package com.RainbowSea.filter;

public class Test {
    public static void main(String[] args) {
        m1();
    }

    private static void m1() {
        System.out.println("m1() begin ");
        m2();
        System.out.println("m1() end ");
    }

    private static void m2() {
        System.out.println("m2() begin ");
        m3();
        System.out.println("m2() end ");
    }

    private static void m3() {
        System.out.println("m3() begin ");

        System.out.println("m3() end ");
    }
}

JavaWeb 中 Filter过滤器

7. 运用 Filter 过滤器的方式优化 oa 项目的一个登录验证:

关于 oa 项目的,大家可以移步至🔜🔜🔜 B/S 结构系统的 缓存机制(Cookie) 以及基于 cookie 机制实现 oa 十天免登录的功能_ChinaRainbowSea的博客-CSDN博客 先了解,有助于后面的阅读。

思路:

有什么情况下不能拦截: 要过滤通过:

目前编写的路径是/* 表示所有请求均拦截:

用户访问 index.jsp 的时候不能拦截, 要放行:
用户登录过了,这个时候,需要放行。
用户要去登录,这个也是不能拦截,要放行:让用户登录。
其他情况:比如,没有登录过,就想访问资源的话,过滤拦截,
登录失败,过滤拦截
用户退出,不能拦截,要让其过去

需要注意的是:这里我们 Filter 过滤器当中的 doFilter() 方法中的 request 是来自: ServletRequest 接口的,当时如下使用的一些方法 sendRedirect() 是来自于: HttpServletRequest 这个接口的,所以我们需要强制类型转换一下。 HttpServletRequest 是 extends 继承了 ServletRequest 接口的。

JavaWeb 中 Filter过滤器

JavaWeb 中 Filter过滤器

package com.RainbowSea.Filter;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import java.io.IOException;

@WebFilter("/*")
public class LoginCheckFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        // 需要强制类型转换以下,因为 下面的一些getServletPath 方法是来自 HttpServletRequest的
        //不是 来自 ServletRequest 的
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        String servletPath = request.getServletPath();  // 获取到浏览器当中的uri

        // 获取session 这个 session 是不不需要新建的
        // 只是获取当前session ,获取不到这返回null,
        HttpSession session = request.getSession(false);  // 获取到服务器当中的session ,没有不会创建的



        // 过滤器:
        /*
        有什么情况下不能拦截: 要过滤通过:
          1. 目前编写的路径是/* 表示所有请求均拦截:

          用户访问 index.jsp 的时候不能拦截, 要放行:
          用户登录过了,这个时候,需要放行。
          用户要去登录,这个也是不能拦截,要放行:让用户登录。
          其他情况:比如,没有登录过,就想访问资源的话,过滤拦截,
          登录失败,过滤拦截
          用户退出,不能拦截,要让其过去


           if ("/dept/list".equals(servletPath)) {
                doList(request, response);
            } else if ("/dept/detail".equals(servletPath)) {
                doDetail(request, response);
            } else if ("/dept/delete".equals(servletPath)) {
                doElete(request,response);
            } else if("/dept/save".equals(servletPath)) {
                doSave(request,response);
            } else if("/dept/modify".equals(servletPath)) {
                doModify(request,response);


         */

        if("/index.jsp".equals(servletPath) || (("/welcome").equals(servletPath)) ||
                ( session != null && session.getAttribute("username") != null)
        || "/user/login".equals(servletPath) || "/user/exit".equals(servletPath)) {
            // 双重的判断,一个是 session 会话域要存在,其次是 会话域当中存储了名为 "username" 的信息

            chain.doFilter(request,response);  // 放行,让其向下一个过滤器,或者是Servlet 执行
        } else {
            response.sendRedirect(request.getContextPath() + "/index.jsp");  // 访问的web 站点的根即可,自动找到的是名为 index.jsp
            // 的欢迎页面(注意这里被优化修改了:局部优先)注意:这里修改了,需要指明index.jsp登录页面了,因为局部优先
        }
    }
}

8. 总结:

  1. Filter 过滤器它是 JavaEE 的规范。也就是接口Filter 过滤器它的作用是:拦截请求,过滤响应。
  2. Filter 过滤器的常用的三个方法:
  • init方法:在Filter对象第一次被创建之后调用,并且只调用一次。
  • doFilter方法:只要用户发送一次请求,则执行一次。发送N次请求,则执行N次。在这个方法中编写过滤规则。
  • destroy方法:在Filter对象被释放/销毁之前调用,并且只调用一次。
  1. 目标Servlet是否执行,取决于两个条件:
  • 第一:在过滤器当中是否编写了:chain.doFilter(request, response); 代码。
  • 第二:用户发送的请求路径是否和Servlet的请求路径一致。
  1. chain.doFilter(request, response); 这行代码的作用:执行下一个过滤器,如果下面没有过滤器了,执行最终的Servlet。

  2. 注意:Filter的优先级,天生的就比Servlet优先级高。

  • /a.do 对应一个Filter,也对应一个Servlet。那么一定是先执行Filter,然后再执行Servlet。
  1. Filter 的执行原理图:
    JavaWeb 中 Filter过滤器

  2. Filter 过滤器拦截路径:

    • /a.do、/b.do、/dept/save。这些配置方式都是精确匹配。
    • /* 匹配所有路径。
    • *.do 后缀匹配。不要以 / 开始
    • /dept/* 前缀匹配
  3. Filter 过滤器的设置执行顺序:两种方式:

  • 在web.xml文件中进行配置的时候,依靠filter-mapping标签的配置位置,越靠上优先级越高。

  • @WebFilter的时候,执行顺序是:比较Filter这个类名。

    • 比如:FilterA和FilterB,则先执行FilterA。
    • 比如:Filter1和Filter2,则先执行Filter1
  1. Filter 过滤器中的责任链设计模式思想:责任链设计模式最大的核心思想:在程序运行阶段,动态的组合程序的调用顺序
  2. 编写 Filter 过滤器的技巧:先想明白一个就是:哪些资源/功能方法是需要验证才能放行的,哪些是不需要验证直接就放行通过的。想明白这两点,基本上编写的 Filter 过滤器没有任何问题了。

9. 最后:

⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐ 感谢如下博主的分享: ⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐

  • https://www.liaoxuefeng.com/wiki/1252599548343744/1266264823560128
  • https://blog.csdn.net/weixin_45007073/article/details/120071622?ops_request
  • https://blog.csdn.net/weixin_45024585/article/details/112749271?ops_request_

限于自身水平,其中存在的错误,希望大家给予指教,韩信点兵——多多益善,谢谢大家,江湖再见,后会有期!!!

JavaWeb 中 Filter过滤器文章来源地址https://www.toymoban.com/news/detail-437154.html

到了这里,关于JavaWeb 中 Filter过滤器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 过滤器Filter

    过滤器Filter

    什么是Filter? Filter表示过滤器,是JavaWeb三大组件(Servlet、FIlter、Listener)之一。 过滤器可以把对资源的请求拦截下来,总而实现一些特殊的功能 使用过滤器后,要想访问web服务器上的资源,必须先经过过滤器,过滤器处理完毕后,才可以访问对应的资源。 过滤器一般完成

    2023年04月12日
    浏览(15)
  • 结果过滤器—MVC项目中结果过滤器(Result Filter)使用

    结果过滤器—MVC项目中结果过滤器(Result Filter)使用

    结果过滤器( ResultFilter ),是对执行的Action结果进行处理的一种AOP思想,适用于任何需要直接环绕 View 或格式化处理的逻辑。结果过滤器可以 替换或更改 Action 结果 。在 IActionResult 执行的前后执行,使用它能够控制Action的执行结果,比如:格式化结果等。需要注意的是,它只

    2024年02月12日
    浏览(48)
  • [Java]过滤器(Filter)

    [Java]过滤器(Filter)

    一、什么是过滤器 过滤器是Servlet的高级特性之一,是实现Filter接口的Java类! 过滤器的执行流程:   从上面的图我们可以发现,当浏览器发送请求给服务器的时候, 先执行过滤器,然后才访问Web的资源。服务器响应Response,从Web资源抵达浏览器之前,也会途径过滤器。 过滤

    2024年02月11日
    浏览(10)
  • java过滤器(Filter)

    java过滤器(Filter)

    原文链接: java过滤器(Filter – 编程屋 目录 1 过滤器简介 2 Filter详细介绍 3 Filter的用法 3.1 用法1  3.2 用法2 filter也称之为过滤器,它是javaWeb三大组件之一(Servlet程序、Listener监听器、Filter过滤器) 作用: 既可以对请求进行拦截,也可以对响应进行处理。 常见场景: 权限检

    2024年02月20日
    浏览(12)
  • SpringCloudGateway--过滤器(内置filter)

    SpringCloudGateway--过滤器(内置filter)

    目录 一、概览 二、内置过滤器 1、StripPrefix 2、AddRequestHeader 3、AddResponseHeader 4、DedupeResponseHeader 5、AddRequestParameter 6、CircuitBreaker 7、FallbackHeaders 8、RequestRateLimiter 9、RedirectTo 10、RemoveRequestHeader 11、RemoveResponseHeader 12、RemoveRequestParameter 13、RewritePath  14、RewriteResponseHeader  15、S

    2024年02月01日
    浏览(16)
  • 布隆过滤器(Bloom Filter)

    布隆过滤器(Bloom Filter)

    通常我们会遇到很多要判断一个元素是否在某个集合中的业务场景,一般想到的是将集合中所有元素保存起来,然后通过比较确定。链表、树、散列表(又叫哈希表,Hash table)等等数据结构都是这种思路。但是随着集合中元素的增加,我们需要的存储空间也会呈现线性增长,

    2024年02月08日
    浏览(11)
  • gateway之过滤器(Filter)详解

    gateway之过滤器(Filter)详解

    在Spring Cloud中,过滤器(Filter)是一种关键的组件,用于在微服务架构中处理和转换传入请求以及传出响应。过滤器位于服务网关或代理中,并通过拦截请求和响应流量来提供各种功能。 过滤器在请求的不同生命周期阶段执行特定的操作,例如鉴权、认证、请求转发、限流、

    2024年02月05日
    浏览(11)
  • 登录校验-Filter-登录校验过滤器

    登录校验-Filter-登录校验过滤器

    目录 思路 登录校验Filter-流程 步骤 流程图 登录校验Filter-代码 过滤器类 工具类 测试登录 登录接口功能请求 其他接口功能请求 前后端联调  前端访问登录接口,登陆成功后,服务端会生成一个JWT令牌,并返回给前端,前端会将JWT令牌保存下来,在同一会话中共享JWT令牌信息

    2024年02月11日
    浏览(9)
  • SpringCloudGateway--过滤器(自定义filter)

    SpringCloudGateway--过滤器(自定义filter)

    目录 一、概览  二、全局过滤器GlobalFilter 三、通过GatewayFilter实现 四、继承AbstractGatewayFilterFactory        当使用Spring Cloud Gateway构建API网关时,可以利用Spring Cloud Gateway提供的内置过滤器(filter)来实现对请求的处理和响应的处理。过滤器可以在请求被路由之前或之后被执

    2024年02月06日
    浏览(11)
  • springboot中使用filter过滤器

    springboot中使用filter过滤器

    filter过滤器其实是JavaEE中的规范,JavaWeb中的三大组件是filter过滤器、listener监听器,servlet服务。 过滤器的作用就是把请求拦截下来,从而对请求进行一些特殊操作,比如检验用户是否登录,判断权限,设置编码格式、敏感字符处理等。 filter过滤器中有三个方法: 分别是初始

    2024年02月08日
    浏览(11)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包