在代码之前,讲一下用filter实现GZIP压缩的原理:

因为GZIP压缩之后,是从服务器端传输到浏览器端,从servlet到浏览器(从jsp到浏览器),其实是response带回内容,所以我们要在filter中对从servlet端响应回来的response进行操作,因为写内容是response中的writer或者outputStream来完成的,所以我们首先要把response中的writer或者outputStream中的内容取出来,这里我选择了writer进行操作(writer和outputStream其实皆可),但是问题又来了,response.getWriter.write();直接就写出了内容(因为response内部的writer其实是PrintWriter),定位输出到浏览器页面显示上了,并没有缓存起来,那么我们该怎么解决这个问题呢?

思路如下:

使用装饰者模式对response中的getWriter方法进行重写,以便提供一个带缓存的writer,让操作者得到的writer实际上write是定位在writer构造传入的缓存中的(这个缓存可以使用我们之前讲的ByteArrayOutputStream或者CharArrayWriter,这类输出流的好处是,带有一个toByteArray和toCharArray的方法,可以直接获得流内部的内容发)重写HttpServletResponse,同样因为HttpServletResponse只是一个接口,所以要继承自HttpServletResponse的实现类:HttpServletResponseWrapper,(同之前讲过的这篇博文,request和response都是实现wrapper);然后在我们重写之后的response中提供直接获得内部缓存内容的方法,然后我们就可以在filter中正常压缩啦!

servlet中的代码:

package day04;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; public class ContentTestGZIPFilterServlet extends HttpServlet { private static final long serialVersionUID = 3505039773816640152L; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
// 准备内容
StringBuffer sb = new StringBuffer();
for (int i=1; i<=3000; i++) {
sb.append("abcd");
}
System.out.println("压缩前的数据大小:"+sb.toString().getBytes().length);
// 输出到浏览器
response.getWriter().write(sb.toString());
} public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8"); } }

web.xml中filter的配置:

  <filter>
<filter-name>GZIPFilter</filter-name>
<filter-class>day04.GZIPFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>GZIPFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

filter的代码:

package day04;

import java.io.ByteArrayOutputStream;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.zip.GZIPOutputStream; 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.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper; public class GZIPFilter implements Filter { public void destroy() {}
public void init(FilterConfig filterConfig) throws ServletException {} public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//1)过滤请求 //创建一个response的装饰者对象
MyHttpResponse myResponse = new MyHttpResponse((HttpServletResponse)response);
/**
* 放行
*/
chain.doFilter(request, myResponse); //3)过滤响应
//从缓存容器对象得到压缩前的内容
//注意:response对象中没有方法获取实体内容,怎么办?
char[] content = myResponse.getCharArray(); //gzip压缩
ByteArrayOutputStream buf = new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(buf);
gzip.write(new String(content).getBytes());
gzip.finish();
byte[] result = buf.toByteArray(); //告诉浏览器发送内容的压缩格式
myResponse.setHeader("content-encoding", "gzip"); //输出:
/*
* 注意:
* 这里的输出不能使用PrintWriter了
* 因为PrintWriter的输出定位已经在了内部的流缓存中了,不能定位到界面输出了
* 所以要使用OutputStream
*/
response.getOutputStream().write(result);
//myRresponse.getWriter().write(new String(result,0,result.length));
}
} /**
* HttpServletResponse的装饰者类
*/
class MyHttpResponse extends HttpServletResponseWrapper{ private HttpServletResponse response; //定义一个缓存容器对象:必须是自带缓冲的流,不能是包装流:即构造方法还需要传入一个writer的流
CharArrayWriter charArray = new CharArrayWriter(); /**
* 提供一个获取charArray内容的方法
*/
public char[] getCharArray(){
return charArray.toCharArray();
} public MyHttpResponse(HttpServletResponse response) {
super(response);
this.response = response;
} /**
* 重写getWriter()方法,让其返回一个带缓存功能的PrintWriter
*/
@Override
public PrintWriter getWriter() throws IOException {
/**
* 现在已经创建了一个带CharArrayWriter缓存容器的PrintWriter了,
* 如果我们调用带缓存PrintWriter对象的write()方法,那么内容会直接写入到CharrArrayWriter缓存容器中。
*/
return new PrintWriter(charArray);
} }

使用filter过滤GZIP压缩(二)的更多相关文章

  1. Springboot 之 Filter 实现 Gzip 压缩超大 json 对象

    简介 在项目中,存在传递超大 json 数据的场景.直接传输超大 json 数据的话,有以下两个弊端 占用网络带宽,而有些云产品就是按照带宽来计费的,间接浪费了钱 传输数据大导致网络传输耗时较长 为了 ...

  2. PHP中zlib扩展实现GZIP压缩输出各种方法总结

    一般情况下我们出现大量数据传输理希望减少服务器的带宽压力,会采取一种方式来压缩文件传输,php中用zlib也可以实现gzip压缩输出,下面我们来看GZIP压缩输出各种方法总结. GZIP(GNU-ZI ...

  3. Filter之——GZIP全站压缩

    GZIP压缩:将压缩后的文本文件,发送给浏览器,减少流量. 一.进行gzip压缩条件: 1.请求头:Accept-Encoding : gzip  告诉服务器,该浏览器支持gzip压缩. 2.响应头: ...

  4. JSP Filter,GZIP压缩响应流

    url:http://hi.baidu.com/xhftx/blog/item/fbc11d3012648711ebc4af59.html 关键词:JSP,Filter,Servlet,GZIP 现在 ...

  5. 网站访问优化(二):开启apache服务器gzip压缩

    昨天,把带宽从1M升级到2M,使用cdn版本的jquery之后,网站访问速度由平均5s(在禁止缓存的情况下,使用缓存大概在2.8s)下降到2.8s的样子. 今天,继续优化. 第1步:   把图片进行了 ...

  6. gzip压缩JavaScript

    为了提高客户端的体验效果,RIA开发逐渐兴起.这样会项目中会充斥的大量的JavaScript代码,与此同时会消耗客户端浏览器性能.对于 Ext 实现的 one page one application ...

  7. Apache启用GZIP压缩网页传输方法

    一.gzip介绍 Gzip是一种流行的文件压缩算法,如今的应用十分广泛,尤其是在Linux平台.当应用Gzip压缩到一个纯文本文件时,效果是很明显的,大约能够降低70%以上的文件大小.这取决于文件里的 ...

  8. GZIP压缩提高网络传输效率

    [spring]通过GZIP压缩提高网络传输效率(可以实现任何资源的gzip压缩.包括AJAX) gzip是http协议中使用的一种加密算法,客户端向web服务器端发出了请求后,通常情况下服务器端会将 ...

  9. Apache启用GZIP压缩网页传输

    首先我们先了解Apache Gzip的相关资料. 一.gzip介绍 Gzip是一种流行的文件压缩算法,现在的应用十分广泛,尤其是在Linux平台.当应用Gzip压缩到一个纯文本文件时,效果是非常明显的 ...

随机推荐

  1. Linux系统下Java 转换Word到PDF时,结果文档内容乱码的解决方法

    本文分享在Linux系统下,通过Java 程序代码将Word转为PDF文档时,结果文档内容出现乱码该如何解决.具体可参考如下内容: 1.问题出现的背景 在Windows系统中,使用Spire.Doc ...

  2. Centos7 firewall开放3306端口 笔记

    1. 开启端口 // zone -- 作用域 // add-port=80/tcp -- 添加端口,格式为:端口/通讯协议 // permanent -- 永久生效,没有此参数重启后失效 firewa ...

  3. StringIO和BytesIO的用法

    数据读写有两种方式: 1.直接读写.案例 import openpyxl def write_excel(): f = openpyxl.Workbook() # 创建工作簿 # sheet1 = f ...

  4. ASP.NET中<%=%>、<%%>、<%@%>、<%#%>的用法与区别

    1.<%= %> 里面放变量名,获取后台的变量值,直接输入变量到页面上,里面放的变量名,未经过encode eg: 后台: seession["ab"]=ab; 前台: ...

  5. Qt 入门 ---- 如何在程序窗口显示图片?

    步骤: 1. 选择资源(准备图片) 2. 加载资源(导入图片) 3. 使用资源(显示图片) 具体操作流程: ① 从网上寻找合适的图片素材,下载到本地,在项目根目录下创建一个images文件夹存储程序中 ...

  6. Python - 浅拷贝的四种实现方式

    浅拷贝详解 https://www.cnblogs.com/poloyy/p/15084277.html 方式一:使用切片 [:] 列表 # 浅拷贝 [:] old_list = [1, 2, [3, ...

  7. Sql Server备份表,动态生成表名称

    1.常用的数据库备份表语句 SELECT * INTO tableNameNew FROM tableName 2.动态备份表,且备份表名称后面增加三位随机字符和当前日期 1 DECLARE @bak ...

  8. 手写Pascal解释器(三)

    目录 一.part7 抽象语法树和具体语法树(解析树) 代码实现 二.part8 一.part7 资料来源:https://ruslanspivak.com/lsbasi-part7/ 看作者博客的标 ...

  9. ListPopupWindow和Popupwindow的阴影相关问题demo总结

    Popupwindow: 优点:可以通过setBackgroundDrawable()来重新设置阴影. 缺点:当AnchorView是可移动的,比如移动到屏幕的左右边界.左下角.右下角时,Popupw ...

  10. 探索HashMap源码 一行一行解析 jdk1.7版本

    今天我们来说一说,HashMap的源码到底是个什么? 面试大厂这方面一定会经常问到,很重要的.以jdk1.7 为标准    先带着大家过一遍 是由数组.链表组成 , 数组的优点是:每个元素有对应下标, ...