zoukankan      html  css  js  c++  java
  • Filter 过滤器

    Filter 是拦截Request请求的对象:在用户的请求访问资源前处理 ServletRequest 以及 ServletResponse。

    Filter 可用于日志记录、加解密、Session检查、图像文件保护等。通过 Filter 可以拦截处理某个资源或者某些资源。

    Filter 配置可以通过 Annotation 或者部署描述符(web.xml)来完成,但是,当一个资源或者某些资源需要被多个 Filter 所使用且他们的触发顺序很重要时,只能通过部署描述符(web.xml)来配置。

    Filter API

    Filter 相关的接口都在 javax.servlet 包中,包含:Filter、FilterConfig、FilterChain

    Filter 接口  public interface Filter

    Filter 的实现必须实现 javax.servlet.Filter 接口,该接口包含三个方法

    default void init(FilterConfig filterConfig) throws ServletException  // 一般在应用开始时,容器会调用该方法初始化Filer,只调用一次。FilterConfig由容器传入init方法中;default表名该方法有默认实现
    void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException  
    // 当Servlet容器每次处理Filter相关的资源时,会调用该Filter实例的doFilter方法。 default void destroy() // 一般在应用停止的时候,容器会调用该方法来销毁Filter;default表名该方法有默认实现

    在 Filter 的 doFilter的实现中,最后一行需要调用 FilterChain 中的 doChain 方法。注意 Filter 的 doFilter 方法里的第3个参数,就是 filterChain 的实例:

    filterChain.doFilter(request, response)

    只用在 Filter 链条中最后一个 Filter 里调用的 FilterChain.doFilter(),才会触发处理资源的方法。如果在结尾处没有调用 FilterChain.doFilter()的方法,则该Request请求中止,后面的处理就会中断。

    FilterChain 接口  public interface FilterChain

    该接口只有一个方法 doFilter(request, response) ,该方法和Filter接口中的doFiler(request, response, filterChain)方法定义不一样。

    void doFilter(ServletRequest request, ServletResponse response) throws java.io.IOException, ServletException  //

    一般 filter 都是一个链,部署描述符(web.xml)中配置了几个就是几个,一个一个的连在一起: request --> filter 1 --> filter 2 --> filter 3 --> ... --> request resource 

    chain.doFilter(request, reponse) 将请求转发给过滤器链的下一个filter,如果没有下一个filter,那就是请求的资源。

    如果在filter中忘记最后的chain.doFilter(request, response),会导致无法访问到请求资源。

    FilterConfig 接口  public interface FilterConfig

    该接口有四个方法

    java.lang.String getFilterName()  //
    ServletContext getServletContext()  // 
    java.lang.String getInitParameter(java.lang.String name)  // 返回指定参数
    java.util.Enumeration<java.lang.String> getInitParameterNames()  // 返回参数名称的Enumeration对象,如果没有给这个Filter配置任何参数,则返回空的Enumeration

    Filter 配置

    当完成 Filter 的实现之后,就可以开始配置 Filter 了,步骤如下

    (1)确认哪些资源需要使用这个 Filter 拦截处理

    (2)配置 Filter 的初始化参数值,这些参数可以在 Filter 的 init 方法中读取到

    (3)给 Filter 取一个名字。

    注册 Filter

    可以通过@WebFilter进行注册,也可以通过部署描述符(web.xml)进行注册。

    但是当多个 Filter 应用到同一个资源,Filter的触发顺序将变得非常重要,才是只能使用部署描述符来管理 Filter,即指定哪个 Filter 先触发。

    使用@WebFilter需要熟悉下面的参数,这些参数都是在 javax.servlet.annotation.WebFilter 中定义的,所有参数都是可选的

    asyncSupported   // boolean
    description      // java.lang.String
    dispatcherTypes  // DispatcherType[]
    displayName      // java.lang.Sring
    filterName       // java.lang.String
    initParams       // WebInitParam[]
    largeIcon        // java.lang.String
    servletNames     // java.lang.String[]
    smallIcon        // java.lang.String
    urlPatterns      // java.lang.String[]
    value            // java.lang.String[]

    使用@WebFilter的例子

    @WebFilter (filterName = "Security Filter", urlPatterns = { "/*" },
       initParams = {
         @WebInitParam(name = "frequency", value = "1909"),
         @WebInitParam(name = "resolution", value = "1024")
       }
    )

    使用部署描述符(web.xml)的例子

    <filter>
      <filter-name>Security Filter</filter-name>
      <filter-class>filterClass的全限定名</filter-class>
      <init-param>
        <param-name>frequency</param-name>
        <param-value>1909</param-value>
      </init-param>
      <init-param>
        <param-name>resolution</param-name>
        <param-value>1024</param-value>
      </init-param>
    </filter>
    <filter-mapping>
      <filter-name>Security Filter</filter-name>
      <url-pattern>/*</url-pattern>
    </filter-mapping>

    利用部署描述符配置 Filter 的触发顺序,例如 Filter 1 需要在 Filter 2 之前被触发,那么在部署描述符中,Filter 1 需要配置在 Filter 2 之前,如下

    <filter>
      <filter-name>Filter 1</filter-name>
      <filter-class>实现Filter接口的类的全限定名</filter-class>
    </filter>
    <filter>
      <filter-name>Filter 2</filter-name>
      <filter-class>实现Filter接口的类的全限定名</filter-class>
    </filter>
    <fitler-mapping>
      ...
    <filter-mapping>

    实例一  日志 Filter

    package app09a.filter;
    
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.Date;
    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.annotation.WebFilter;
    import javax.servlet.annotation.WebInitParam;
    import javax.servlet.http.HttpServletRequest;
    
    @WebFilter(filterName = "LoggingFilter", urlPatterns = { "/*" },
        initParams = { @WebInitParam(name = "logFileName", value = "log.txt"),
                       @WebInitParam(name = "prefix", value = "URI: ")
                     }
    )
    public class LoggingFilter implements Filter {
        private PrintWriter logger;
        private String prefix;
        
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            prefix = filterConfig.getInitParameter("prefix");  // 获取初始化参数
            String logFileName = filterConfig.getInitParameter("logFileName");  // 获取初始化参数
            String appPath = filterConfig.getServletContext().getRealPath("/");  // 获取真实路径值,此处为“C:Program FilesJavaapache-tomcat-9.0.12webappsapp09a”
            try {
                logger = new PrintWriter(new File(appPath, logFileName));  // 新建文件和PrintWriter对象
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                throw new ServletException(e.getMessage());
            }
        }
        @Override
        public void destroy() {
            System.out.println("destroying filter");
            if (logger != null) {
                logger.close();
            }
        }
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
            System.out.println("LoggingFilter.doFilter");
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            logger.println(new Date()+ " " + prefix + httpServletRequest.getRequestURI());
            logger.flush();
            filterChain.doFilter(request, response);  // 
        }
    }
    <!-- test.jsp -->
    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>test</title>
    </head>
    <body>
        This is a test for filter.
    </body>
    </html>

    实例二 图像文件保护 Filter

    package app09a.filter;
    
    import java.io.IOException;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    
    @WebFilter(filterName = "ImageProtectorFilter", urlPatterns = { "*.png", "*.jpg", "*.gif" })
    public class ImageProtectorFilter implements Filter {
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            String referer = httpServletRequest.getHeader("referer");  // HTTP referer 属性是 header 的一部分,当浏览器向web服务器发送请求的时候,一般会带上 referer,告诉服务器我是从哪个页面链接过来的。
            System.out.println("referer: " + referer);                 // 直接访问图片时,referer 的值为 null
            if ( referer != null) {                                    // 通过JSP页面访问图片时,referer 的值为 http://localhost:8080/app09a/image.jsp
                filterChain.doFilter(request, response);               
            } else {                                                   
                throw new ServletException("Image not available!");
            }
        }
    }
    <!-- image.jsp -->
    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>image</title>
    </head>
    <body>
        <img src='image/logo.jpg' />  <!-- 当浏览器通过该链接获取图片资源时,他也将该页面的 URL 作为 Header 的 referer 值传到服务器中 -->
    </body>
    </html>

    实例三 下载基数 Filter

    package app09a.filter;
    
    import java.io.File;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.util.Properties;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    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.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    
    @WebFilter(filterName = "DownloadCounterFilter", urlPatterns = { "/*" })
    public class DownloadCounterFilter implements Filter {
        ExecutorService executorService = Executors.newSingleThreadExecutor();  // 单线程池
        Properties downloadLog;  // Properties类对象主要用于读取Java的配置文件
        File logFile;
        
        @Override
        public void destroy() {
            executorService.shutdown();  // 关闭线程池
        }
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            String appPath = filterConfig.getServletContext().getRealPath("/");  // 获取该应用的绝对路径
            logFile = new File(appPath, "downloadLog.txt");
            if (!logFile.exists()) {
                try {
                    logFile.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            downloadLog = new Properties();
            try {
                downloadLog.load(new FileReader(logFile));  // 从文件中载入
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            final String uri = httpServletRequest.getRequestURI();
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    String property = downloadLog.getProperty(uri);
                    if (property == null) {
                        downloadLog.setProperty(uri, "1");
                    } else {
                        int count = 0;
                        try {
                            count = Integer.parseInt(property);
                        } catch (NumberFormatException e) {
                            e.printStackTrace();
                        }
                        count ++;
                        downloadLog.setProperty(uri, Integer.toString(count));
                    }
                    try {
                        downloadLog.store(new FileWriter(logFile), "");
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
            filterChain.doFilter(request, response);
        }
    }
  • 相关阅读:
    centos 配置puTTY rsa自动登录
    Linux LVM 简单操作
    linux 系统下有sda和hda的硬件设备分别代表什么意思
    Centos 安装Sublime text 3
    编译安装MySQL-5.7.13
    药品查询网的数据库
    获得Android设备的唯一序列号
    Android中设置TextView的颜色setTextColor
    介绍几款网页数据抓取软件 分类: 业余 2015-08-07 18:09 5人阅读 评论(0) 收藏
    网上处方药物手册Rxlist 及其药学信息资源 分类: 业余 2015-08-07 14:16 8人阅读 评论(0) 收藏
  • 原文地址:https://www.cnblogs.com/0820LL/p/9906783.html
Copyright © 2011-2022 走看看