javaweb组件 Filter 过滤器的使用及过滤器链详解

一.简介

过滤器,顾名思义就是对事物进行过滤的,在Web中的过滤器,就是对请求进行过滤,我们使用过滤器,就可以对请求进行拦截,然后做相应的处理,实现许多特殊功能。如登录控制,权限管理,继而不用在每个接口都写一遍一样的"验证"逻辑
在这里插入图片描述

二.使用 (模拟登录验证)

1.首先创建一个项目,如果使用filter的话,需要引入servlet-api的jar包 这个jar可以在tomcat中找到(tomcat目录下 lib文件夹)

在这里插入图片描述
在这里插入图片描述

2.创建一个servlet 模拟主功能

@WebServlet(urlPatterns = "/manage/manageServlet")
public class manageServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("登录成功 manageServlet执行~");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

3.此时我们需要对执行该接口进行登录校验,用户名和密码均为123,则才能访问。加上filter

public class loginCheckFilter implements Filter {

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

    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
        String username = httpServletRequest.getParameter("username");
        String password = httpServletRequest.getParameter("password");
        //登录合法 跳转到manageServlet
        if("123".equals(username) && "123".equals(password)){
            System.out.println("登录成功!");
            //继续执行目标方法
            filterChain.doFilter(servletRequest, servletResponse);
            System.out.println("目标方法结束~");
        }else{
            //登录不合法
            System.out.println("登录失败!");
            httpServletResponse.setContentType("text/html;charset=utf-8");
            PrintWriter writer = httpServletResponse.getWriter();
            writer.println("校验不通过!");
        }
    }

    @Override
    public void destroy() {

    }
}

4.web.xml配置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>loginCheckFilter</filter-name>
        <filter-class>com.aiit.servlet.loginCheckFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>loginCheckFilter</filter-name>
        <url-pattern>/manage/*</url-pattern>
    </filter-mapping>

</web-app>
   解读: filter一般写在其它servlet的前面
    1. 观察我们发现filter 配置和 servlet 非常相似. filter也是被tomcat管理和维护
    2. url-pattern 就是当请求的url 和 匹配的时候,就会调用该filter
    3. /manage/* 第一个 / 解析成 http://ip:port/工程路径
    4. 完整的路径就是 http://ip:port/工程路径/manage/* 当请求的资源url满足该条件时
    都会调用filter 
    如: http://localhost:8080/manage/manageServlet?username=123&password=123

5.如果你嫌web.xml配置麻烦,可以在过滤器类上使用注解 @WebFilter(urlPatterns = {“/manage/*”}) ,即可实现相同效果

在这里插入图片描述

6.测试验证

  1. 输入账号和密码不为 123 即不符合规则 提示 校验不通过!
    在这里插入图片描述
    控制台打印出登录失败
    在这里插入图片描述
  2. 输入账号密码为123 即符合条件 查看控制台输出
    在这里插入图片描述

三.过滤器链

含义:一个请求的路径匹配上了两个过滤器 这样就形成了过滤器链 。匹配执行的顺序按照web.xml中配置的顺序
在这里插入图片描述

1.创建两个servlet - AFilter BFilter 模拟调用链

  1. AFilter
public class AFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        System.out.println("AFilter---> 线程id=" +
                Thread.currentThread().getId());

        System.out.println("AFilter doFilter 的前置代码...");
        System.out.println("执行 AFilter doFilter()");
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("AFilter doFilter 的后置代码...");
    }

    @Override
    public void destroy() {

    }
}

  1. BFilter
public class BFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        System.out.println("BFilter---> 线程id=" +
                Thread.currentThread().getId());

        System.out.println("BFilter doFilter 的前置代码...");

        System.out.println("执行 BFilter doFilter()");
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("BFilter doFilter 的后置代码...");
    }

    @Override
    public void destroy() {

    }
}

3.web.xml


    <filter>
        <filter-name>AFilter</filter-name>
        <filter-class>com.aiit.servlet.AFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>AFilter</filter-name>
        <url-pattern>/admin/* </url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>BFilter</filter-name>
        <filter-class>com.aiit.servlet.BFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>BFilter</filter-name>
        <url-pattern>/admin/*</url-pattern>
    </filter-mapping>
由上述代码可看出,AFilter和BFilter都监听同一个url /admin/*   
此时 如果你访问,则先走到AFilter,因为AFilter在web.xml中配置在BFilter前面

4.执行
在这里插入图片描述
查看控制台
在这里插入图片描述

总结:
1.多个 filter 和目标资源在一次 http 请求,在同一个线程中 
2. 当一个请求 url 和 filter 的 url-pattern 匹配时, 才会被执行, 如果有多个匹配上,就会 顺序执行,形成一个 filter 调用链(底层可以使用一个数据结构搞定) 
3. 多个 filter 共同执行时,因为是一次 http 请求, 使用同一个 request 对象 
4. 多个 filter 执行顺序,和 web.xml 配置顺序保持一致. 
5. chain.doFilter(req, resp)方法 将执行下一个过滤器的 doFilter 方法, 如果后	面没有过滤器, 则执行目标资源。 
6. 小结:注意执行过滤器链时, 顺序是(用前面的案例分析) Http请求 -> A 过滤	器 dofilter() -> A 过滤器前置代码 -> A 过滤器 chain.doFilter() -> B 过滤器 	dofilter() -> B 过滤器前置代 码 -> B过滤器 chain.doFilter() -> 目标文件 -> 	B过滤器后置代码 -> A过滤器后置代码 -> 返回给浏览器页面/数据

版权声明:本文为qq_42978230原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。