美文网首页知识库
JavaWeb之Filter过滤器教程

JavaWeb之Filter过滤器教程

作者: Java_Evan | 来源:发表于2024-01-16 00:04 被阅读0次

    什么是Filter过滤器?

    Filter在Web开发中通常被称为过滤器,是一种用于拦截处理请求和响应的组件。它可以在请求到达目标资源之前进行拦截,也可以对响应进行拦截。通过使用过滤器,可以对请求参数进行校验、对响应内容进行压缩和加密等操作,从而提高系统的安全性、性能和可靠性。

    过滤器可以串联在处理请求的整个路径中,对请求进行预处理和后处理。例如,可以过滤掉恶意请求、对请求参数进行统一格式化等。在处理响应时,可以统一设置响应头、对响应内容进行压缩等。

    • Filter 过滤器它是 JavaWeb 的三大组件之一。
    • Filter 过滤器它是 JavaEE 的规范。也就是接口
    • Servlet3.0可以用注解@WebFilter,Servlet2.5可以使用xml文件配置。
    • Filter在配置时,和servlet一样,也可以配置通配符,例如 @WebFilter("*.do")表示拦截所有以.do结尾的请求

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

    假设有一个admin目录,使用用户登录之后才可以访问这个目录下的资源。

    思考:
    我们知道,用户登录之后都会把用户登录的信息保存到 Session 域中。所以要检查用户是否登录,可以判断 Session 中否包含有用户登录的信息即可!

    <body>
      <%
        Object user = session.getAttribute("user");
        // 如果等于 null,说明还没有登录
        if (user == null) {
            request.getRequestDispatcher("/login.jsp").forward(request,response);
            return;
        }
      %>
    
    <h2>这是info.jsp</h2>
    </body>
    

    结论:
    这种在jsp页面方式虽然能判断用户是否登录限制资源访问,但如果在html页面下无法使用这种判断方式,有了局限性,所以最好是使用Filte过滤器限制访问。

    Filter工作流程

    Filter工作流程图

    Filter案例实操

    Filter 过滤器的使用步骤:

    1、编写一个类去实现 Filter 接口

    2、实现过滤方法 doFilter()

    3、到 web.xml 中去配置 Filter 的拦截路径

    <body>
        这是登录页面。login.jsp 页面 <br>
        <form action="http://localhost:8080/day05_cookie/login" method="get">
            用户名:<input type="text" name="username"/> <br>
            密 码:<input type="password" name="password"/> <br>
            <input type="submit" />
        </form>
    </body>
    
    public class AdminFilter implements Filter {
        public AdminFilter() {
            System.out.println("Filter实现类的构造器初始化操作...");
        }
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println("Filter过滤器初始化操作...");
        }
    
        /**
         * doFilter():专门用于拦截请求,过滤响应
         * @param servletRequest
         * @param servletResponse
         * @param filterChain
         * @throws IOException
         * @throws ServletException
         */
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            var httpServletRequest = (HttpServletRequest) servletRequest;
            var session = httpServletRequest.getSession();
            var user = session.getAttribute("user");
            if (user == null) {
                //如果等于null,则没有登录成功
                servletRequest.getRequestDispatcher(File.separator + "login.jsp").forward(servletRequest,servletResponse);
            } else {
                //登录成功,放行当前请求和响应
                filterChain.doFilter(servletRequest,servletResponse);
            }
        }
    
        @Override
        public void destroy() {
            System.out.println("Filter过滤器销毁操作...");
        }
    }
    
    public class LoginServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setContentType("text/html;charset=UTF-8");
            var username = req.getAttribute("username");
            var password= req.getAttribute("password");
            if ("admin".equals(username) && "123456".equals(password)) {
                req.getSession().setAttribute("user",username);
                resp.getWriter().write("登录成功");
            } else {
                req.getRequestDispatcher(File.separatorChar + "login.jsp").forward(req,resp);
            }
        }
    }
    
    <!-- 配置Filter过滤器 -->
    <filter>
        <!-- Filter实现类的别名 -->
        <filter-name>adminFilter</filter-name>
        <!-- Filter实现类的全类名 -->
        <filter-class>com.evan.java.AdminFilter</filter-class>
    </filter>
    <!-- 映射当前请求到Filter实现类 -->
    <filter-mapping>
        <!-- 当前请求的拦截路径到哪个Filter使用 -->
        <filter-name>adminFilter</filter-name>
        <!-- 配置拦截路径:
                / 表示请求地址是 http://ip:port/工程路径/  映射到当前工程模块的web目录
                /admin/* 表示请求地址是 http:ip:port/工程路径/admin/*
             -->
        <url-pattern>/admin/*</url-pattern>
    </filter-mapping>
    
    <!-- 配置servlet访问 -->
    <servlet>
        <servlet-name>loginServlet</servlet-name>
        <servlet-class>com.evan.java.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>loginServlet</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mapping>
    

    结论:
    当login.jsp登录成功时当前请求执行目标资源,Filter检查满足规则则会放行,继续执行下一个操作;当登录失败去执行当前请求的目标资源时会被拦截跳转到login.jsp

    Filter生命周期

    public class AdminFilter implements Filter {
        public AdminFilter() {
            System.out.println("1.Filter实现类的构造器初始化操作...");
        }
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println("2.Filter过滤器初始化操作...");
        }
    
        /**
         * doFilter():专门用于拦截请求,过滤响应
         * @param servletRequest
         * @param servletResponse
         * @param filterChain
         * @throws IOException
         * @throws ServletException
         */
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            System.out.println("3.doFilter执行请求和响应的拦截操作...");
        }
    
        @Override
        public void destroy() {
            System.out.println("4.Filter过滤器销毁操作...");
        }
    }
    

    Filter声明周期的执行过程:

    1. 执行FIlter实现类的构造器
    2. 执行Filter初始化方法
    3. 执行Filter的doFilter拦截方法
    4. 执行FIlter的销毁方法
      步骤1和2是在web工程启动时执行,后续web工程没有关闭,再次执行Filter操作会执行步骤3,步骤3在每次拦截到请求时执行,步骤4在工程停止时执行。

    FilterConfig类

    FilterConfig 类见名知义,它是 Filter 过滤器的配置文件类。
    Tomcat 每次创建 Filter对象的时候,也会同时创建一个 FilterConfig 类,这里包含了 Filter 配置文件的配置信息。
    FilterConfig 类的作用是获取 filter 过滤器的配置内容 :
    1、获取 Filter 的名称 filter-name 的内容

    2、获取在 Filter 中配置的 init-param 初始化参数

    3、获取 ServletContext 对象

    public class AdminFilter implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println("Filter过滤器初始化操作...");
            //获取Filter的名称filter-name的内容
            System.out.println("filter-name值:" + filterConfig.getFilterName());
            //获取web.xml中配置的init-param初始化参数
            System.out.println("初始化参数username的值是:" + filterConfig.getInitParameter("username"));
            //获取ServletContext对象
            System.out.println("ServletContext对象:" + filterConfig.getServletContext());
        }
    }
    
    <!-- 配置Filter过滤器 -->
    <filter>
        <!-- Filter实现类的别名 -->
        <filter-name>adminFilter</filter-name>
        <!-- Filter实现类的全类名 -->
        <filter-class>com.evan.java.AdminFilter</filter-class>
        <!-- 配置Filter初始化参数值 -->
        <init-param>
            <param-name>username</param-name>
            <param-value>admin</param-value>
        </init-param>
    </filter>
    <!-- 映射当前请求到Filter实现类 -->
    <filter-mapping>
        <!-- 当前请求的拦截路径到哪个Filter使用 -->
        <filter-name>adminFilter</filter-name>
        <!-- 配置拦截路径:
                / 表示请求地址是 http://ip:port/工程路径/  映射到当前工程模块的web目录
                /admin/* 表示请求地址是 http:ip:port/工程路径/admin/* 映射到当前工程模块的web目录下的admin目录
             -->
        <url-pattern>/admin/*</url-pattern>
    </filter-mapping>
    

    FilterChain 过滤器链

    Filter: 过滤器 。
    Chain :链,链条。
    FilterChain就是过滤器链条。


    FilterChain工作流程图
    多个FilterChain执行的特点:

    1、所有Filter和目标资源默认都执行在同一个线程中。
    2、多个Filter共同执行的时候,它们都使用同一个Request对象。

    FilterChain.doFilter方法的作用:

    1、执行下一个Filter过滤器(如果有Filter)
    2、执行目标资源(下一步没有Filter执行目标资源)
    在多个Filter过滤器执行的时候,他们执行的优先顺序是由他们在web.xml中配置从上而下的顺序决定。

    案例实操
    //Filter1实现类
    public class Filter1 implements Filter {
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            System.out.println("Filter1 前置代码");
            filterChain.doFilter(servletRequest,servletResponse);
            System.out.println("Filter1 后置代码");
        }
    }
    
    //Filter2实现类
    public class Filter2 implements Filter {
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            System.out.println("Filter2 前置代码");
            filterChain.doFilter(servletRequest,servletResponse);
            System.out.println("Filter2 后置代码");
        }
    }
    
    <filter>
        <filter-name>filter1</filter-name>
        <filter-class>com.evan.java.Filter1</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>filter1</filter-name>
        <url-pattern>/filterTest.jsp</url-pattern>
    </filter-mapping>
    
    <filter>
        <filter-name>filter2</filter-name>
        <filter-class>com.evan.java.Filter2</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>filter2</filter-name>
        <url-pattern>/filterTest.jsp</url-pattern>
    </filter-mapping>
    

    FilterChain的执行结果:
    Filter1 前置代码
    Filter1的线程:http-nio-8080-exec-3
    Filter2 前置代码
    Filter2的线程:http-nio-8080-exec-3
    filterText.jsp
    Filter2 后置代码
    Filter1 后置代码

    FIilterChain的执行顺序:
    先执行Filter链的所有前置代码以及doFIlter的拦截方法,然后执行Filter链的所有后置代码;同时它们的都是在一个线程中按照web.xml中的filter配置的先后顺序执行。
    如果采取的是注解的方式进行配置,那么过滤器链的拦截顺序是按照全类名的先后顺序排序的。
    如果采取的是xml的方式进行配置,那么按照配置的先后顺序进行排序。

    Filter 的拦截路径

    • 精确匹配
      <url-pattern>/target.jsp</url-pattern>
      以上配置的路径,表示请求地址必须为:http://ip:port/工程路径/target.jsp
    • 目录匹配
      <url-pattern>/admin/*</url-pattern>
      以上配置的路径,表示请求地址必须为:http://ip:port/工程路径/admin/*
    • 后缀名匹配
      <url-pattern>*.html</url-pattern>
      以上配置的路径,表示请求地址必须以.html 结尾才会拦截到
      <url-pattern>*.do</url-pattern>
      以上配置的路径,表示请求地址必须以.do 结尾才会拦截到
      <url-pattern>*.action</url-pattern>
      以上配置的路径,表示请求地址必须以.action 结尾才会拦截到

    结论:
    Filter 过滤器它只关心请求的地址是否匹配,不关心请求的资源是否存在!!!

    相关文章

      网友评论

        本文标题:JavaWeb之Filter过滤器教程

        本文链接:https://www.haomeiwen.com/subject/zobcodtx.html