拦截过滤器模式

栏目: Java · 发布时间: 5年前

内容简介:表示层请求处理机制接收许多不同类型的请求,这些请求需要不同类型的处理。有些请求只是转发到适当的处理程序组件,而其他请求必须在进一步处理之前进行修改,审核或解压缩。拦截过滤器模式的最好例子之一是Spring Security 的 DelegatingFilterProxy,它将拦截HTTP请求并进行身份验证检查。Spring安全性构建在过滤器链上。让我们看看

表示层请求处理机制接收许多不同类型的请求,这些请求需要不同类型的处理。有些请求只是转发到适当的处理程序组件,而其他请求必须在进一步处理之前进行修改,审核或解压缩。

拦截过滤器模式的最好例子之一是Spring Security 的 DelegatingFilterProxy,它将拦截HTTP请求并进行身份验证检查。Spring安全性构建在过滤器链上。

让我们看看 拦截过滤器模式 如何通过示例解决问题。为简单起见,这种模式分为若干部分,如问题,动因,解决方案,实施等。

目录

问题

动因

解决方案

说明

结构 - 类图,序列图

参与者和责任

履行

后果

适用性

问题

(问题部分描述了开发人员面临的设计问题)

需要对客户端Web请求和响应进行预处理和后处理。当请求进入Web应用程序时,它通常必须在主处理阶段之前通过多个入口测试。例如,

  • 客户端是否已通过身份验证?
  • 客户端是否有有效的会话?
  • 客户端的IP地址是否来自可信网络?
  • 请求路径是否违反任何约束?
  • 客户端使用什么编码来发送数据?
  • 我们是否支持客户端的浏览器类型?其中一些检查是测试,导致是或否答案,确定是否继续处理。其他检查将输入数据流操作为适合于处理的形式。您希望对客户端Web请求和响应进行预处理和后处理。

动因

(本节描述了列出影响问题和解决方案的原因和动机。动因列表显示了人们可能选择并使用模式的理由)

  • 您希望跨请求进行集中、通用的处理,例如检查每个请求的数据编码方案,记录有关每个请求的信息或压缩传出响应。
  • 您希望预处理和后处理组件与核心请求处理服务松散耦合,以方便不引人注目的添加和删除。
  • 您希望预处理和后处理组件彼此独立且自包含以便于重用。

解决方案

(此处解决方案部分简要介绍了解决方案的方法,并详细介绍了解决方案)

使用拦截过滤器作为可插拔过滤器来预处理和后处理请求和响应。过滤器管理器将松散耦合的过滤器组合在一个链中,将控制权委托给适当的过滤器。通过这种方式,您可以以各种方式添加、删除和组合这些过滤器,而无需更改现有代码。

结构

类图

拦截过滤器模式

序列图

拦截过滤器模式

参与者

过滤器 (Filter)- 在请求处理程序执行请求之前或之后执行特定任务的过滤器。  

过滤链(Filter Chain) - 过滤链带有多个过滤器,有助于在目标上按照定义的顺序执行它们。

目标 (Target )- 目标对象是请求处理程序   

过滤器管理器(Filter Manager) - 过滤器管理器管理过滤器和过滤器链。   

客户端(Client) - 客户端是向Target对象发送请求的对象。

执行

第1步: 创建 过滤器( Filter) 界面。

<b>public</b>  <b>interface</b>  Filter {
    <b>public</b>  <b>void</b>  execute(String  request);
}

第2步: 创建具体过滤器 - AuthenticationFilter,DebugFilter。

<b>public</b> <b>class</b> AuthenticationFilter implements Filter {
   <b>public</b> <b>void</b> execute(String request){
      System.out.println(<font>"Authenticating request: "</font><font> + request);
   }
}
</font>
<b>public</b> <b>class</b> DebugFilter implements Filter {
   <b>public</b> <b>void</b> execute(String request){
      System.out.println(<font>"request log: "</font><font> + request);
   }
}
</font>

第3步: 创建 目标 (Target )

<b>public</b> <b>class</b> Target {
   <b>public</b> <b>void</b> execute(String request){
      System.out.println(<font>"Executing request: "</font><font> + request);
   }
}
</font>

第4步: 创建 过滤链( Filter Chain)

<b>import</b> java.util.ArrayList;
<b>import</b> java.util.List;

<b>public</b> <b>class</b> FilterChain {
   <b>private</b> List<Filter> filters = <b>new</b> ArrayList<Filter>();
   <b>private</b> Target target;

   <b>public</b> <b>void</b> addFilter(Filter filter){
      filters.add(filter);
   }

   <b>public</b> <b>void</b> execute(String request){
      <b>for</b> (Filter filter : filters) {
         filter.execute(request);
      }
      target.execute(request);
   }

   <b>public</b> <b>void</b> setTarget(Target target){
      <b>this</b>.target = target;
   }
}

第5步: 创建 过滤器管理器( FilterManager)

<b>public</b> <b>class</b> FilterManager {
   FilterChain filterChain;

   <b>public</b> FilterManager(Target target){
      filterChain = <b>new</b> FilterChain();
      filterChain.setTarget(target);
   }
   <b>public</b> <b>void</b> setFilter(Filter filter){
      filterChain.addFilter(filter);
   }

   <b>public</b> <b>void</b> filterRequest(String request){
      filterChain.execute(request);
   }
}

第6步: 创建 客户端 (Client)

<b>public</b> <b>class</b> Client {
   FilterManager filterManager;

   <b>public</b> <b>void</b> setFilterManager(FilterManager filterManager){
      <b>this</b>.filterManager = filterManager;
   }

   <b>public</b> <b>void</b> sendRequest(String request){
      filterManager.filterRequest(request);
   }
}

步骤7: 使用 客户端 演示拦截过滤器设计模式

<b>public</b> <b>class</b> InterceptingFilterDemo {
   <b>public</b> <b>static</b> <b>void</b> main(String[] args) {
      FilterManager filterManager = <b>new</b> FilterManager(<b>new</b> Target());
      filterManager.setFilter(<b>new</b> AuthenticationFilter());
      filterManager.setFilter(<b>new</b> DebugFilter());

      Client client = <b>new</b> Client();
      client.setFilterManager(filterManager);
      client.sendRequest(<font>"HOME"</font><font>);
   }
}
</font>

第8步: 验证输出。

Authenticating request: HOME
request log: HOME
Executing request: HOME

标准过滤策略

servlet 2.3规范包括一个标准机制,用于构建过滤器链,并从这些链中不显眼地添加和删除过滤器。

过滤器围绕接口构建,并通过修改Web应用程序的部署描述符以声明方式添加或删除。

javax.servlet.Filter(接口)

过滤器是对资源请求(servlet或静态内容)或资源响应(或两者)执行过滤任务的对象。过滤器在doFilter方法中执行过滤。

每个Filter都可以访问FilterConfig对象,从中可以获取其初始化参数,例如,可以使用ServletContext的引用,以加载过滤任务所需的资源。

过滤器在Web应用程序的部署描述符中配置。

本设计中已确定的示例如下:

  1. 验证过滤器
  2. 记录和审核过滤器
  3. 图像转换过滤器
  4. 数据压缩过滤器
  5. 加密过滤器
  6. 标记过滤器
  7. 触发资源访问事件的过滤器
  8. XSL / T过滤器
  9. Mime型链式过滤器

javax.servlet.FilterChain(接口)

FilterChain是servlet容器向开发人员提供的对象,它提供对资源的筛选请求的调用链的视图。过滤器使用FilterChain调用链中的下一个过滤器,或者如果调用过滤器是链中的最后一个过滤器,则调用链末尾的资源。

示例

这个策略的示例是创建一个过滤器,它对任何编码类型的请求进行预处理,以便在核心请求处理代码中对每个请求进行类似的处理。为什么有必要这样做?包含文件上载的HTML表单使用与大多数表单不同的编码类型。

因此,通过simplegetParameter()调用无法获得伴随上载的表单数据  。所以,我们创建了两个预处理请求的过滤器,将所有编码类型转换为单一的一致格式。我们选择的格式是将所有表单数据作为请求属性提供。

示例1 - 基本过滤器 - 标准过滤策略

<b>public</b> <b>class</b> BaseEncodeFilter implements 
      javax.servlet.Filter {
  <b>private</b> javax.servlet.FilterConfig myFilterConfig;

  <b>public</b> BaseEncodeFilter()     {  }

  <b>public</b> <b>void</b> doFilter(
    javax.servlet.ServletRequest servletRequest, 
    javax.servlet.ServletResponse servletResponse,
    javax.servlet.FilterChain filterChain) 
  throws java.io.IOException,
    javax.servlet.ServletException {
    filterChain.doFilter(servletRequest, 
        servletResponse);
  }

  <b>public</b> javax.servlet.FilterConfig getFilterConfig() 
  {
    <b>return</b> myFilterConfig; 
  }
    
  <b>public</b> <b>void</b> setFilterConfig(
    javax.servlet.FilterConfig filterConfig) {
      myFilterConfig = filterConfig;
  }
}
<b>public</b> <b>class</b> StandardEncodeFilter 
  <b>extends</b> BaseEncodeFilter {
  <font><i>// Creates new StandardEncodeFilter</i></font><font>
  <b>public</b> StandardEncodeFilter()   {  }

  <b>public</b> <b>void</b> doFilter(javax.servlet.ServletRequest 
    servletRequest,javax.servlet.ServletResponse 
    servletResponse,javax.servlet.FilterChain 
    filterChain) 
  throws java.io.IOException, 
    javax.servlet.ServletException {

    String contentType = 
      servletRequest.getContentType();
    <b>if</b> ((contentType == <b>null</b>) || 
      contentType.equalsIgnoreCase(
        </font><font>"application/x-www-form-urlencoded"</font><font>))     {
      translateParamsToAttributes(servletRequest, 
        servletResponse);
    }

    filterChain.doFilter(servletRequest, 
      servletResponse);
  }

  <b>private</b> <b>void</b> translateParamsToAttributes(
    ServletRequest request, ServletResponse response)
  {
    Enumeration paramNames = 
        request.getParameterNames();

    <b>while</b> (paramNames.hasMoreElements())     {
      String paramName = (String) 
          paramNames.nextElement();

      String [] values;

      values = request.getParameterValues(paramName);
      System.err.println(</font><font>"paramName = "</font><font> + paramName);
      <b>if</b> (values.length == 1)
        request.setAttribute(paramName, values[0]);
      <b>else</b>
        request.setAttribute(paramName, values);
    }
 }
}
</font>

示例2- MultipartEncodeFilter - 标准过滤策略

<b>public</b> <b>class</b> MultipartEncodeFilter <b>extends</b> 
  BaseEncodeFilter {
  <b>public</b> MultipartEncodeFilter() { }
  <b>public</b> <b>void</b> doFilter(javax.servlet.ServletRequest 
    servletRequest, javax.servlet.ServletResponse 
    servletResponse,javax.servlet.FilterChain 
    filterChain)
  throws java.io.IOException, 
    javax.servlet.ServletException {
    String contentType = 
      servletRequest.getContentType();   
    <font><i>// Only filter this request if it is multipart </i></font><font>
    </font><font><i>// encoding                </i></font><font>
    <b>if</b> (contentType.startsWith(
                </font><font>"multipart/form-data"</font><font>)){
      <b>try</b> {
        String uploadFolder = 
          getFilterConfig().getInitParameter(
              </font><font>"UploadFolder"</font><font>);
        <b>if</b> (uploadFolder == <b>null</b>) uploadFolder = </font><font>"."</font><font>;

        </font><font><i>/** The MultipartRequest class is: 
        * Copyright (C) 2001 by Jason Hunter 
        * <jhunter@servlets.com>. All rights reserved. 
        **/</i></font><font>
        MultipartRequest multi = <b>new</b> 
          MultipartRequest(servletRequest, 
                           uploadFolder,
                           1 * 1024 * 1024 );
        Enumeration params = 
                 multi.getParameterNames();
        <b>while</b> (params.hasMoreElements()) {
          String name = (String)params.nextElement();
          String value = multi.getParameter(name);
          servletRequest.setAttribute(name, value);
        }

        Enumeration files = multi.getFileNames();
        <b>while</b> (files.hasMoreElements()) {
          String name = (String)files.nextElement();
          String filename = multi.getFilesystemName(name);
          String type = multi.getContentType(name);
          File f = multi.getFile(name);
          </font><font><i>// At this point, do something with the </i></font><font>
          </font><font><i>// file, as necessary</i></font><font>
        }
      }
      <b>catch</b> (IOException e)
      {
        LogManager.logMessage(
          </font><font>"error reading or saving file"</font><font>+ e);
      }
    } </font><font><i>// end if</i></font><font>
    filterChain.doFilter(servletRequest, 
                         servletResponse);
  } </font><font><i>// end method doFilter()</i></font><font>
}
</font>

部署描述符 - 标准过滤策略

<filter>
    <filter-name>StandardEncodeFilter</filter-name>
    <display-name>StandardEncodeFilter</display-name>
    <description></description>
    <filter-<b>class</b>> corepatterns.filters.encodefilter.
            StandardEncodeFilter</filter-<b>class</b>>
  </filter>
  <filter>
    <filter-name>MultipartEncodeFilter</filter-name>
    <display-name>MultipartEncodeFilter</display-name>
    <description></description>
    <filter-<b>class</b>>corepatterns.filters.encodefilter.
            MultipartEncodeFilter</filter-<b>class</b>>
    <init-param>
      <param-name>UploadFolder</param-name>
      <param-value>/home/files</param-value>
    </init-param>
 </filter>

<filter-mapping>
    <filter-name>StandardEncodeFilter</filter-name>
    <url-pattern>/EncodeTestServlet</url-pattern>
  </filter-mapping>
  <filter-mapping>
    <filter-name>MultipartEncodeFilter</filter-name>
    <url-pattern>/EncodeTestServlet</url-pattern>
  </filter-mapping>

后果

  • 使用松散耦合的处理程序集中控制
  • 提高可重用性
  • 声明性和灵活的配置
  • 信息共享效率低下

适用性

使用截取过滤器模式时

  • 系统使用预处理或后处理请求
  • 系统应该执行身份验证/授权/记录或跟踪请求,然后将请求传递给相应的处理程序
  • 您需要一种模块化方法来配置预处理和后处理方案

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Linux内核设计的艺术

Linux内核设计的艺术

新设计团队 / 机械工业出版社华章公司 / 2011-6-20 / 79.00元

关于Linux内核的书已经不计其数,但这本书却是独树一帜的,它的内容代表着Linux内核研究成果的世界顶尖级水平,它在世界范围内首次提出并阐述了操作系统设计的核心指导思想——主奴机制,这是所有操作系统研究者的一笔宝贵财富。本书可能也代表着同类图书的顶尖水平,是一本真正能引导我们较为容易地、极为透彻地理解Linux内核的经典之作,也可能是当前唯一能从本质上指引我们去设计和开发拥有自主知识产权的操作系......一起来看看 《Linux内核设计的艺术》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具