过滤器与包装器

  过滤器允许你拦截请求,也允许你控制响应。Filter很像Servlet,容器管理过滤器的生命周期。和Servlet类似,过滤器也有init()和destroy()方法,对应于servlet的doGet()/doPost(),过滤器则有一个doFilter()方法。过滤器也需要在DD中声明,过滤器的运行顺序也将在DD中声明。

1.过滤器中的生命周期

  首先要有一个inti(),它在服务器启动时执行。最常见的实现是在inti()中保存一个FilterConfig的引用,以备过滤器以后使用(获取过滤器参数等)。

  真正的工作在doFilter()中完成,它在用户每次请求时执行。doFilter方法有3个参数:

一个ServletRequest(不是HttpServletRequest);

一个ServletResponse(不是HttpServletResponse);

一个FilterChain,过滤器并不知道请求所涉及的其他过滤器,但是必须有人知道过滤器执行的顺序,这个人就是FilterChain,它由DD中指定的filter元素驱动。FilterChain的doFilter()方法来调用下一个过滤器或servlet;

最后是destroy(),它在撤销实例之前完成所需要的清理工作。

2.声明和确定过滤器顺序

  在DD中配置过滤器时,通常会做3件事:

1)声明过滤器和过滤器参数:

在DD中声明:

使用动态注入的方式声明:

2)将过滤器映射到想要过滤的web资源;

3)组织这些映射,创建过滤器调用顺序;

当多个过滤器映射到一个给定资源时,容器会使用以下规则:

  • 先找到与URL模式匹配的所有过滤器,并按照在DD中声明的顺序组成一个链。
  • 再找到与<servlet-name>匹配的过滤器,并放在链中。

  4)过滤器可以直接应用于直接来之客户的请求,但是如果请求来自于转发、包含、错误处理,过滤器就无法起到作用。servlet 2.4提供了<dispatcher>元素解决这个问题。

 3.包装器

  servlet API中的包装器功能及其强大,它们为你要包装的东西实现了所需的所有方法,并将所有调用委托给底层的请求或相应对象。你要做的只是扩展某个包装器,如果要在哪些方法中做些特殊的定制工作,只要覆盖这些方法就可以了。包装器类是使用装饰模式的一个典型例子。

  创建一个特定版本的请求或响应,这在创建过滤器时实在太常用了。所以Sun创建了4个“便利类”,一边更容易地完成这个任务:

  • ServletRequestWrapper
  • HttpServletRequestWrapper
  • ServletResponseWrapper
  • HttpServletResponseWrapper

  请求包装器是指利用HttpServletRequestWrapper类将请求中的内容进行统一修改,例如修改请求字符编码、替换字符、权限验证等。

  响应包装器是指利用HttpServletResponseWrapper类将相应中的内容进行统一修改,例如压缩输出内容、替换输出内容等。因为HttpServletResponse不能缓存输出内容,所以在doFilter()之后过滤器再想处理输出为时已晚,此时servlet已经直接将输出返回给客户。所以需要自定义一个具备缓存功能的response,这样在doFilter()之后过滤器可以进行输出的处理。

原文地址:https://www.cnblogs.com/juaner767/p/5513156.html