过滤器原理及使用

 

过滤器

  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视频教程。

原文地址:https://www.cnblogs.com/liu-Gray/p/4897284.html