• 过滤器


    概念

      在容器调用Servlet的service()方法前,Servlet并不会知道有请求的到来,而在Servlet的service()方法运行后,容器真正对浏览器进行HTTP响应之前,浏览器也不会知道Servlet真正的响应是什么。过滤器(Filter)正如其名称所示,是介于Servlet之前,可拦截过滤浏览器对Servlet的请求,也可以改变Servlet对浏览器的响应
      性能评测、用户验证、字符替换、编码设置等需求,基本上与应用程序的业务需求没有直接的关系,只是应用程序额外的元件服务之一。你可能只是短暂需要它,或者需要整个系统应用相同设置,不应该为了一时的需要而修改代码强加入原有业务流程中。例如,性能的评测也许只是开发阶段才需要的,上线之后就要拿掉性能评测的功能,如果直接将性能评测的代码编写在业务流程中,那么要拿掉这个功能,就又得再修改一次源代码。因此,如性能评测、用户验证、字符替换、编码设置这类的需求,应该设计为独立的元件,随时可以加入应用程序中,也随时可以移除,或随时可以修改设置而不用修改原有的程序。这类元件就像是一个过滤器,安插在浏览器与Servlet中间,可以过滤请求与响应而作进一步的处理。并可以视需求抽换过滤器或调整过滤器的顺序,也可以针对不同的URL应用不同的过滤器。甚至在不同的Servlet间请求转发或包含时应用过滤器

    小提示
      性能评测,记录请求与响应间的时间差。
      字符替换,假设有个留言版程序已经上线并正常运作中,但是现在发现,有些用户会在留言中输入一些HTML标签。基于安全性的考量,不希望用户输入的HTML标签直接出现在留言中而被浏览器当作HTML的一  部分。例如,并不希望用户在留言中输入< a href=" ">www.sina.com.cn</ a>这样的信息,不想信息在留言显示中直接变成超链接,让用户有机会在留言版中打广告。这时我们希望将一些HTML字符过滤掉,如将<、> 角括号置换为HTML实体字符&lt;与&gt;。 


    声明

    方法一:在实现HttpFilter的类上标注@WebFilter

    @WebFilter("/*")
    public class TestFilter extends HttpFilter {
        @Override
        protected void doFilter(
             HttpServletRequest request, HttpServletResponse response, FilterChain chain)
                    throws IOException, ServletException {
             // ...
        }
    }
    Java Code

    方法二:在web.xml中声明

    <web-app ...>
        <filter>
            <filter-name>testFilter</filter-name>
            <filter-class>com.Test.TestFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>testFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    </web-app>
    Xml Code 

    过滤策略的指定

    指定过滤策略时,除了URL模式之外,也可以通过Servlet名称来指定,这可以通过@WebServlet的servletNames来设置。

    方式一:注解方式

    @WebFilter(servletNames={"SomeServlet"})
    Java Code

    方式二:web.xml方式,通过 <filter-mapping> 中的 <servlet-name> 标签來設定。下面的Demo会使用这种方式。

    <filter-mapping>
        <filter-name>performance</filter-name>
        <servlet-name>SomeServlet</servlet-name>
    </filter-mapping>
    Xml Code

    如果同时具备<url-pattern>与<servlet-name>,则先比对<url-pattern>,再比对<servlet-name>。


    过滤器初始化参数设置

    方式一:注解方式

    @WebFilter(
        urlPatterns={"/*"}, 
        initParams={
            @WebInitParam(name = "PARAM1", value = "VALUE1"),
            @WebInitParam(name = "PARAM2", value = "VALUE2")
        }
    )
    public class TestFilter extends HttpFilter {
        private String PARAM1;
        private String PARAM2;
    
        @Override
        public void init() throws ServletException {
            PARAM1 = getInitParameter("PARAM1");
            PARAM2 = getInitParameter("PARAM2");
        }
        
        //...
    }
    Java Code

    方式二:web.xml方式,web.xml中的设置会覆盖注解方式的设置

        <filter>
            <filter-name>TestFilter</filter-name>
            <filter-class>com.test.TestFilter</filter-class>
            <init-param>
                <param-name>PARAM1</param-name>
                <param-value>VALUE1</param-value>
            </init-param>
            <init-param>
                <param-name>PARAM2</param-name>
                <param-value>VALUE2</param-value>
            </init-param>
        </filter>
    Xml Code

    触发策略 

    触发过滤器的时机,默认是浏览器发出请求。如果是那些通过RequestDispatcher的forward()或include()来转发或包含的请求,需要设置@WebFilter的dispatcherTypes

    方式一:注解方式

    @WebFilter(
        urlPatterns={"/some"}, 
        dispatcherTypes={
            DispatcherType.FORWARD, DispatcherType.INCLUDE, 
            DispatcherType.REQUEST, DispatcherType.ERROR, DispatcherType.ASYNC
        }
    )
    Java Code

    方式二:web.xml方式

    <filter-mapping>
        <filter-name>SomeFilter</filter-name>
        <servlet-name>*.do</servlet-name>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
        <dispatcher>ERROR</dispatcher>
        <dispatcher>ASYNC</dispatcher>
    </filter-mapping>
    View Code

    如果不设置任何dispatcherTypes,默认为REQUEST。
    FORWARD是指通过RequestDispatcher的forward()而来的请求可以套用过滤器。
    INCLUDE是指通过RequestDispatcher的include()而来的请求可以套用过滤器。
    ERROR是指由容器处理例外而转发过来的请求可以触发过滤器。
    ASYNC是指异步处理的请求可以触发过滤器。


    过滤器执行顺序

    如果有某个URL或Servlet会应用多个过滤器,则根据<filter-mapping>在web.xml中出现的先后顺序,来决定过滤器的运行顺序。


    性能过滤器Demo

    package com.test;
    
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import java.io.IOException;
    
    @WebFilter(filterName = "testFilter")
    public class TestFilter implements Filter {
        private FilterConfig filterConfig;
        public void init(FilterConfig filterConfig) throws ServletException {
            this.filterConfig = filterConfig;
        }
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            long begin = System.currentTimeMillis();
            chain.doFilter(request, response);
            System.err.println("Request process in " + (System.currentTimeMillis() - begin) + " milliseconds");
        }
        public void destroy() { }
    }
    Filter Code  
    package com.test;
    
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    @WebServlet(urlPatterns = "/", name = "myServlet")
    public class MyServlet extends HttpServlet {
        public void doGet(HttpServletRequest request, HttpServletResponse response) {
            doPost(request, response);
        }
    
        public void doPost(HttpServletRequest request, HttpServletResponse response) {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    Servlet Code
    <?xml version="1.1" encoding="UTF-8"?>
    <web-app xmlns="http://java.sun.com/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                  http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
             version="3.0">
      <display-name>Archetype Created Web Application</display-name>
    
      <filter-mapping>
        <filter-name>testFilter</filter-name>
        <servlet-name>myServlet</servlet-name>
      </filter-mapping>
    </web-app>
    web.xml Code

    测试方法:

      1、浏览器访问

      2、查看控制台会输出字符串——“Request process in 3000 milliseconds”


    API简介

      在doFilter()方法中进行service()方法的前置处理,而后决定是否调用FilterChain的doFilter()方法。如果调用了FilterChain的doFilter()方法,就会运行下一个过滤器,如果没有下一个过滤器了,就调用请求目标Servlet的service()方法。如果因为某个情况(如用户没有通过验证)而没有调用FilterChain的doFilter(),则请求就不会继续交给接下来的过滤器或目标Servlet,这时就是所谓的拦截请求。

      FilterChain的doFilter()实现,概念上类似以下代码:

           Filter filter = filterIterator.next();
            if (filter != null) {
                filter.doFilter(request, response, this);
            } else {
                targetServlet.service(request, response);
            }

      在陆续调用完Filter实例的doFilter()仍至Servlet的service()之后,流程会以堆栈顺序返回,所以在FilterChain的doFilter()运行完毕后,就可以针对service()方法做后续处理。


    Servlet 4.0

      实现Filter接口是定义Filter的方式,然而,在Servlet4.0中,新增了GenericFilter类,目的类似于 GenericServlet,GenericFilter 將 FilterConfig 的設定、Filter 初始參數的取得做了封裝,并且在有参的init()方法里最后调用了一个无参的init()方法。
      同时也新增了 HttpFilter,繼承自 GenericFilter。
      因此,在 Servlet 4.0 中,若要定義 Filter,可以繼承 HttpFilter。

    @WebFilter("/*")
    public class TestFilter extends HttpFilter {
      @Override
      protected void doFilter(
        HttpServletRequest request, HttpServletResponse response, FilterChain chain)
        throws IOException, ServletException {
          long begin = System.currentTimeMillis();
          chain.doFilter(request, response);
          getServletContext().log("Request process in " + (System.currentTimeMillis() - begin) + " milliseconds");
      }
    }

  • 相关阅读:
    Docker学习(二): 镜像的使用与构建
    Docker学习(一): 基本概念
    SVN笔记
    标准Trie字典树学习二:Java实现方式之一
    标准Trie字典树学习一:原理解析
    SQL优化
    企业信息管理系统需求分析及要设计——程序的设计与实现①
    企业信息管理系统需求分析及要设计
    网络版ATM项目的实现——服务端
    网络版ATM项目的实现——客户端
  • 原文地址:https://www.cnblogs.com/Mike_Chang/p/10063284.html
Copyright © 2020-2023  润新知