• 过滤器原理及使用


     

    过滤器

      Servlet过滤器可以对Servlet、JSP和HTML文件过滤。

      过滤器在实际开发中用得较多,是属于较重点的内容。

      主要是处理session信息,登陆请求。也可以启动框架内部的某些。

    Servlet过滤器的概念

      Servlet过滤器是在Java Servlet规范2.3中定义的,它能够对Servlet容器的请求和响应对象进行检查和修改。

      Servlet过滤器本身并不生成请求和响应对象,它只提供过滤作用。

      Servlet过滤器能够在Servlet被调用之前检查Request对象,修改Request Header和Request内容。

      在Servlet被调用之后检查Response对象,修改Response Header和Response内容。

      Servlet过滤器负责过滤的Web组件可以是Servlet、JSP或HTML文件

    Servlet过滤器的过滤过程

     

      过滤器的处理过程是一个链式的过程(FilterChain),即多个过滤器组成一个链,依次处理,最后交给过滤器之后的资源。

      其中链式过滤过程中也可以直接给出响应,即返回,而不是向后传递。

     

    Filter接口

      所有的Servlet过滤器类都必须实现javax.servlet.Filter接口。

      这个接口含有3个过滤器类必须实现的方法:

      init(FilterConfig):这是Servlet过滤器的初始化方法,Servlet容器创建Servlet过滤器实例后将调用这个方法。

      在这个方法中可以读取web.xml文件中Servlet过滤器的初始化参数。

      比如web.xml中声明:

    复制代码
        <filter>
            <filter-name>MyFilter1</filter-name>
            <filter-class>com.mengdd.filter.MyFilter1</filter-class>
            <init-param>
                <param-name>hello</param-name>
                <param-value>world</param-value>
            </init-param>
            <init-param>
                <param-name>name</param-name>
                <param-value>zhang</param-value>
            </init-param>
        </filter>
    复制代码

      在MyFilter1中:

    复制代码
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
            String paramValue1 = filterConfig.getInitParameter("hello");
            String paramValue2 = filterConfig.getInitParameter("name");
    
            ServletContext context = filterConfig.getServletContext();
        }
    复制代码

      注意:一旦一个过滤器启动失败,会导致整个Web应用启动失败。

      doFilter(ServletRequest, ServletResponse, FilterChain):这个方法完成实际的过滤操作。

      当客户请求访问与过滤器关联的URL时,Servlet容器将先调用过滤器的doFilter方法

      FilterChain参数用于访问后续过滤器。

      在这个方法中调用chain.doFilter()方法,用于调用过滤器链中后续过滤器的doFilter()方法,假如没有后续过滤器,那么就把客户请求传给相应的Web组件。

      如果在这个方法中没有调用chain.doFilter()方法,客户请求不会到达所访问的Web组件。

     

      destroy():Servlet容器在销毁过滤器实例前调用该方法,在这个方法中可以释放Servlet过滤器占用的资源。

    过滤器的例子

      比如用户登录之后,将信息传入session中,之后的其他页面入口可能需要 检测是否存在session,以避免直接在地址栏输入地址访问页面而造成的session中没有用户信息的情况,如果在每个Servlet或JSP前面都 要判断session中是否有相应属性,会有很多的代码重复,用过滤器可以很好地解决这个问题,如果不含登录信息,即转向到用户登录页面。

    复制代码
    package com.mengdd.filter;
    
    import java.io.IOException;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    public class LoginFilter implements Filter {
    
        @Override
        public void destroy() {
    
            // 由Web容器调用
            // 在这里进行资源释放
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {
            System.out.println("doFilter invoked!");
    
            HttpServletRequest req = (HttpServletRequest) request;
            HttpSession session = req.getSession();// 获取请求的session,如果没有,会创建一个新的session
    
            // 对不需要进行过滤的请求进行事先筛选操作
            String requestURI = req.getRequestURI();
            if (requestURI.endsWith("login.jsp")
                    || requestURI.endsWith("LoginServlet")) {
                chain.doFilter(request, response);
                return;
            }
    
            if (null == session.getAttribute("username")) {
    
                // session中没有用户名属性,说明是新的session,之前没有登录
                // 用过滤器完成了整个Web应用中未登录情况的处理
                ((HttpServletResponse) response).sendRedirect("login.jsp");
    
                // 这里注意,由于本filter配置的<url-pattern>/*</url-pattern>是针对所有地址的
                // 所以请求发送到login.jsp页面也会需要先经过此过滤器,造成重定向的递归重复调用
                // 所以需要对请求的URI进行判断
            }
            else {
                // 按照过滤链继续往下走
                chain.doFilter(request, response);
            }
    
        }
    
        @Override
        public void init(FilterConfig arg0) throws ServletException {
            System.out.println("Filter init");
            // 过滤器是非常特殊的一个Servlet,它会在容器启动的时候得到初始化
            // 过滤器的启动失败会导致Web应用启动失败
    
        }
    
    }
    复制代码

      过滤器的配置和Servlet的配置相似,只不过URL配置的是要过滤请求的URL:

    复制代码
        <!-- filter一般配置在所有的Servlet上面 -->
        <filter>
            <filter-name>LoginFilter</filter-name>
            <filter-class>com.mengdd.filter.LoginFilter</filter-class>
        </filter>
    
        <filter-mapping>
            <filter-name>LoginFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
        <!-- /*表示所有地址,即所有请求都会被送到这个过滤器 -->
    复制代码

      可以做很多练习例子,比如可以创建一个NoteFilter过滤器,它可以拒绝列在黑名单上的客户访问留言簿。(黑名单通过过滤器参数设置)。  

      也可以利用Filter进行一些关键词修改替换的工作。

     

    串联过滤器的例子

      几点说明:

      1.串联过滤器的顺序是按照在web.xml中的配置顺序为准的。

    复制代码
        <filter>
            <filter-name>MyFilter1</filter-name>
            <filter-class>com.mengdd.filter.MyFilter1</filter-class>
            <init-param>
                <param-name>hello</param-name>
                <param-value>world</param-value>
            </init-param>
            <init-param>
                <param-name>name</param-name>
                <param-value>zhang</param-value>
            </init-param>
        </filter>
        <filter>
            <filter-name>MyFilter2</filter-name>
            <filter-class>com.mengdd.filter.MyFilter2</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>MyFilter1</filter-name>
            <url-pattern>/InfoServlet</url-pattern>
        </filter-mapping>
        <filter-mapping>
            <filter-name>MyFilter2</filter-name>
            <url-pattern>/InfoServlet</url-pattern>
        </filter-mapping>
    复制代码

      2.在Servlet过滤器中能访问application范围内的共享数 据:先调用FilterConfig的getServletContext()方法获得ServletContext,再调用 ServletContext的getAttribute()方法来获得application范围内的共享数据。

    复制代码
    package com.mengdd.filter;
    
    import java.io.IOException;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    
    public class MyFilter1 implements Filter {
    
        @Override
        public void destroy() {
    
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {
    
            System.out.println("MyFilter1 --> doFilter invoked!");
            System.out.println("MyFilter1 --> before chain.doFilter()");
            chain.doFilter(request, response);
            System.out.println("MyFilter1 --> after chain.doFilter()");
    
        }
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
            String paramValue1 = filterConfig.getInitParameter("hello");
            String paramValue2 = filterConfig.getInitParameter("name");
    
            ServletContext context = filterConfig.getServletContext();
        }
    
    }
    复制代码
    复制代码
    package com.mengdd.filter;
    
    import java.io.IOException;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    
    public class MyFilter2 implements Filter{
    
        @Override
        public void destroy() {
            
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {
            
            System.out.println("MyFilter2 --> doFilter invoked!");
            System.out.println("MyFilter2 --> before chain.doFilter()");
            chain.doFilter(request, response);
            System.out.println("MyFilter2 --> after chain.doFilter()"); 
        }
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            
        }
    
    }
    复制代码

    参考资料

      圣思园张龙老师Java Web视频教程。

  • 相关阅读:
    Oracle数据库用户密码设为无限期
    CentOS 7设置网卡开机自动启用
    求凹多边形的视觉中心,不是质心、重心
    autocad数据交换格式dxf读取
    gis资源站
    geotools的空间索引使用——R树和四叉树
    JTS的泰森多边形
    Geotools的delaunry三角剖分
    geotools的最短路径实现
    java多线程
  • 原文地址:https://www.cnblogs.com/liu-Gray/p/4897284.html
Copyright © 2020-2023  润新知