过滤器和包装类

过滤器允许你拦截请求。最棒的是,servlet对此一无所知


过滤器

3.3 描述Web容器请求处理模型;编写和配置过滤器;创建请求或响应包装器;给定一个设计问题,描述如何应用过滤器或包装器。
11.1 给定一个场景描述,列出了一系列问题,选择能够解决这些问题的模式。你必须了解的模式包括:
1. 拦截过滤器
2. 模型-视图-控制器
3. 前端控制器
4. 服务定位器
5. 业务委托
6. 传输对象
11.1 对于以下设计模式,将各模式与使用该模式可能带来的好处相匹配:
1. 拦截过滤器
2. 模型-视图-控制器
3. 服务定位器
4. 业务委托
5. 传输对象


过滤器

能够过滤一切东西!并且生命周期与servlet很类似。


过滤器是模块化,在DD中配置

顺序由DD来控制!


过滤器在3个方面很像servlet

  1. 容器知道过滤器API。过滤器有自己的API。如果一个Java类实现了Filter接口,对容器来说就有很大不同,这个类会从原先一个普通的Java类摇身一变而成为一个正式的J2EE过滤器。过滤器API的其他成员允许过滤器访问ServletContext,而且可以与其他过滤器链接。
  2. 容器管理过滤器的生命周期。就像servlet一样,过滤器也有一个生命周期。类似于servlet过滤器有init()和destroy()方法。对应于servlet的doGet()/doPost()方法,过滤器则有一个doFilter()方法。
  3. 都在DD中声明。Web应用可以有很多的过滤器,一个给定请求可能导致执行多个过滤器。针对请求要运行哪些过滤器,以及运行的顺序如何,这些都要在DD中声明。

建立请求跟踪过滤器


过滤器的生命周期

每个过滤器都必须实现Filter接口中的三个方法:init()、doFilter()和destroy()。

  1. 首先要有一个init()。容器决定实例化一个过滤器时,就要把握住机会,在init()方法中完成调用过滤器之前的所有初始化任务。前一页显示了最常见的实现;也就是保存FilterConfig对象的一个引用,以备过滤器以后使用。
  2. 真正的工作在doFilter()中完成。每次容器认为应该对当前请求应用过滤器时,就会调用doFilter()方法。doFilter()方法有3个参数:ServletRequest、ServletResponse、FilterChain,过滤器的功能要在doFilter()方法中实现。如果过滤器要把用户记录到一个文件中,就要在doFilter()中完成。你想压缩响应输出吗?也要在doFilter()中实现。
  3. 最后是destroy()。容器决定删除一个过滤器实例时,会调用destroy()方法,这样你就有机会在真正撤销实例之前完成所需的所有清理工作。

过滤器“入栈”

多个过滤器同时工作!


声明和确定过滤器顺序

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

  1. 声明过滤器
  2. 将过滤器映射到你想过滤的Web资源
  3. 组织这些映射,创建过滤器调用序列

如下(简单地说,就是可以过滤url和servlet,顺序是先查找与之匹配的所有url再查找servlet将其按查找顺序组成链):


2.4版本中,过滤器可以应用于请求分派器

除了对url和servlet的过滤,还过滤转发、包含、请求分派和错误处理!


用一个响应端过滤器压缩输出

在servlet完成其工作并从(虚拟)栈弹出后,过滤器还会得到机会执行!

不过事情没有那么简单:

那该如何解决这个问题呢?往下看!


可以实现自己的响应

容器已经实现了HttpServletResponse接口:doFilter()和service()方法就是以这样一个响应作为参数。

实现HttpServletResponse接口也太麻烦了吧,因为方法好多啊!

如何解决?下面!


包装器

servlet API中的包装器类功能极其强大,它们为你要包装的东西实现了所需的所有方法,并将所有调用委托给底层的请求或响应对象。如果想创建定制请求或响应对象,只需派生某个便利请求或响应“包装器”类。包装器包装了实际请求或响应对象,而且把调用委托给(传给)实际的对象,还允许你对定制请求或响应做所需的额外处理

4个“便利”类:

  1. ServletRequestWrapper
  2. HttpServletRequestWrapper
  3. ServletResponseWrapper
  4. HttpServletResponseWrapper

这其实就是装饰器模式


简单的包装器例子


包装器第二版本


具体的代码

过滤器代码:

package com.example.web;import java.io.IOException;
import java.util.zip.GZIPOutputStream;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;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class CompressioinFilter implements Filter{private ServletContext ctx;private FilterConfig cfg;/*** init方法保存配置对象,并保存* servlet上下文对象的一个直接* 引用*/@Overridepublic void init(FilterConfig cfg) throws ServletException {this.cfg = cfg;ctx = cfg.getServletContext();ctx.log(cfg.getFilterName()+" initialized.");}/*** 这个过滤器的核心是用装饰器包装响应对象,它* 用一个压缩I/O流包装输出流,当且仅当客户包* 含一个Accept-Encoding首部(具体为gzip)时,才会完成输出流的压缩。*/@Overridepublic void doFilter(ServletRequest req, ServletResponse resp, FilterChain fc)throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) resp;String valid_encodings = request.getHeader("Accept-Encoding");if(valid_encodings.indexOf("gzip")>-1) {CompressioinResponseWrapper wrappedResp = new CompressioinResponseWrapper(response);wrappedResp.setHeader("Content-Encoding","gzip");//链接下一个组件fc.doFilter(request, wrappedResp);//GZIP压缩流必须“结束”,这也会刷新输出GZIP//流缓冲区,将所有数据发送到原来的响应流//容器处理余下的工作GZIPOutputStream gzos = wrappedResp.getGZIPOutputStream();gzos.flush();ctx.log(cfg.getFilterName() + ": finished the request.");}else {ctx.log(cfg.getFilterName() + ": no encoding performed.");fc.doFilter(request, response);}}//销毁@Overridepublic void destroy() {cfg = null;ctx = null;}}

包装器代码:

package com.example.web;import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.zip.GZIPOutputStream;import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;public class CompressioinResponseWrapper extends HttpServletResponseWrapper {//servlet响应的压缩输出流private GZIPServletOutputStream servletGzipOS = null;//压缩输出流的PrintWriter对象private PrintWriter pw = null;CompressioinResponseWrapper(HttpServletResponse response) {//super构造函数完成装饰器的职责//保存所装饰对象的一个引用,在这//里被装饰的对象就是HTTP响应对象super(response);}//忽略这个方法——输出会得到压缩@Overridepublic void setContentLength(int len) {}public GZIPOutputStream getGZIPOutputStream() {//过滤器使用这个装饰器方法为压缩过//滤器提供一个GZIP输出流的句柄,以便//过滤器“完成”和刷新输出GZIP流return this.servletGzipOS.internalGzipOS;}private Object streamUsed = null;//允许访问所装饰的servlet输出流@Overridepublic ServletOutputStream getOutputStream() throws IOException {if(streamUsed!=null&&streamUsed!=pw) {//仅当servlet还没有访问打印书写器时//允许servlet访问servlet输出流throw new IllegalStateException();}if(servletGzipOS==null) {//用我们的压缩输出流包装原来的servlet输出流servletGzipOS = new GZIPServletOutputStream(getResponse().getOutputStream());streamUsed = servletGzipOS;}return servletGzipOS;}@Overridepublic PrintWriter getWriter() throws IOException {if(streamUsed!=null&&streamUsed!=servletGzipOS) {//当且仅当servlet还没有访问servlet输出//流时,允许servlet访问打印书写器throw new IllegalStateException();}if(pw==null) {/*** 要建立一个打印书写器,必须首先包装servlet输出流* 然后把压缩servlet输出流包装在另外两个输出流装饰器* 中:首先OutputStreamWrite把字符转换为字节,再用* PrintWriter包装OutputStreamWriter对象。*/servletGzipOS = new GZIPServletOutputStream(getResponse().getOutputStream());OutputStreamWriter osw = new OutputStreamWriter(servletGzipOS, getResponse().getCharacterEncoding());pw = new PrintWriter(osw);streamUsed = pw;}return pw;}
}

辅助类:

package com.example.web;import java.io.IOException;
import java.util.zip.GZIPOutputStream;import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;public class GZIPServletOutputStream extends ServletOutputStream{//保存原始GZIP流的一个引用GZIPOutputStream internalGzipOS;@Overridepublic boolean isReady() {return false;}@Overridepublic void setWriteListener(WriteListener arg0) {}//装饰器构造函数GZIPServletOutputStream(ServletOutputStream sos) throws IOException {this.internalGzipOS = new GZIPOutputStream(sos);}@Overridepublic void write(int param) throws IOException {//这个方法把write()调用委托给GZIP压缩流,//从而实现压缩装饰,GZIP压缩流包装了原来的//ServletOutputStreaminternalGzipOS.write(param);}}

本章完。

Head First JSP---随笔十(过滤器的威力)相关推荐

  1. 给JSP页面加过滤器

    很简单的一个功能,如果用户没有登录之前访问其他页面时转到登录页面.用过滤器来实现. 一.在web-xml 中添加: [code] <filter><!-- 是否登录用户的验证filt ...

  2. java 拦截jsp页面_JSP 过滤器

    JSP 过滤器 JSP 和 Servlet 中的过滤器都是 Java 类. 过滤器可以动态地拦截请求和响应,以变换或使用包含在请求或响应中的信息. 可以将一个或多个过滤器附加到一个 Servlet 或 ...

  3. 东软JavaWeb实训记-DAY5-MyBatis框架+jsp传值+登录过滤器

    1.Mybatis:jdbc操作数据库的封装 持久化框架 a)创建 Mybatis 的配置文件: b)sql语句放入映射文件中 2.持久化 :把瞬时状态的数据和持久状态数据转换的机制 瞬时状态:存放在 ...

  4. JSP第十四次课:JSP项目开发高级操作2---在线编辑器应用及前台首页显示商品

    一.在线编辑器KindEditor下载 下载 KindEditor 最新版本,下载之后打开 examples/index.html 就可以看到演示. 下载页面: http://www.kindsoft ...

  5. jsp随笔-工作使用-直播功能

    1.状态功能 <div class="form-group"> <label for="" class="col-md-3 cont ...

  6. android 学习随笔十二(网络:使用异步HttpClient框架)

    使用异步HttpClient框架发送get.post请求 在https://github.com/  搜索 asyn-http https://github.com/search?utf8=✓& ...

  7. android 学习随笔十六(广播 )

    1.广播接收者 BroadcastReceiver 接收系统发出的广播 现实中的广播:电台为了传达一些消息,而发送的广播,通过广播携带要传达的消息,群众只要买一个收音机,就可以收到广播了  Andro ...

  8. 复习C语言随笔 十二

    数组类型 int arr1[3]; //这里的arr1数组和arr2数组都是int型的数组 int arr2[4]; //但它们各属于不同的类型: 前者类型为 int [3] 后者类型为 int [4 ...

  9. 复习C语言随笔 十四

    main函数参数 1.使用main函数的参数,实现一个整数计算器 要求: 程序可以接受三个参数,第一个参数"-a"选项执行加法,"-s"选项执行减法," ...

最新文章

  1. python自然语言处理.词性标注
  2. 十三、java_GUI
  3. deepin启动盘无法引导安装_深度启动盘制作工具(Deepin Boot Maker)怎么安装kubuntu?Deepin Boot Maker图文教程...
  4. 华为荣耀手机指令代码大全_双十二,华为/荣耀手机推荐选购指南,全系列横评推荐,那一款华为/荣耀手机最值得够买...
  5. 深度特征提取方法_深度学习|三维重建:StereoDRNet
  6. java程序弊端_面向对象编程的弊端是什么?
  7. ZOJ-Crashing Balloon
  8. [转]研究生阶段学习规划指导随笔
  9. ros简版Action通讯SimpleAction
  10. wav格式怎么转换成mp3格式
  11. 【旺铺2012分享】导航CSS代码使用修改技巧!
  12. 【专家视点】公域流量的尽头:数字营销回归商业本质(20页精品PPT下载)
  13. 为什么NFT的头像卖这么贵?这与IPFS/FIL有什么联系
  14. HTML静态网页作业——基于html+css+javascript+jquery+bootstarp响应式成都家乡介绍网页
  15. 复选框 全选 以及 获取所有选中的值
  16. 蓝墨云班课与中职计算机课,蓝墨云环境下中职《计算机应用基础》的对分课堂教学研究...
  17. 可禁用计算机服务,Windows 10系统下哪些服务可以关闭?
  18. html表格标题行边框,总结HTML 表格标签
  19. PostgreSQL 用 CTE语法 + 继承 实现平滑拆分大表
  20. Codeforces 题目合集+分类+代码 【Updating...】【361 in total】

热门文章

  1. NYOJ 594 还是A+B
  2. hdu 2112 HDU Today 最短路(Dijkstra算法)
  3. 对搜狗输入法的个人评价
  4. 数据的结构和运算(求和,最大和最小)
  5. [luoguP1773] 符文之语_NOI导刊2010提高(02)(DP)
  6. Lucene实战之基于StandardAnalyzer读写索引
  7. 微信公众平台开发新手教程(图文具体解释)
  8. 使用java调用Web天气服务
  9. 解决springmvc在单纯返回一个字符串对象时所出现的乱码情况(极速版)
  10. 使用JQUERY实现局部页面定时刷新