JSP Filter,GZIP压缩响应流
url:http://hi.baidu.com/xhftx/blog/item/fbc11d3012648711ebc4af59.html
关键词:JSP,Filter,Servlet,GZIP
现在主流浏览器都是支持gzip的。服务器压缩网页后进行传输,可减少传输数据的大小使用户感觉访问速度更快。当然,压缩也会消耗一部分服务器处理时间。
用Filter实现对返回信息的压缩,代码参考Tomcat examples里面的compressionFilters:
GZipStream.java
- import java.io.IOException;
- import java.io.OutputStream;
- import java.util.zip.GZIPOutputStream;
- import javax.servlet.ServletOutputStream;
- public class GZipStream extends ServletOutputStream {
- private GZIPOutputStream zipStream;
- public GZipStream(OutputStream out) throws IOException {
- zipStream = new GZIPOutputStream(out);
- }
- @Override
- public void flush() throws IOException {
- zipStream.flush();
- }
- @Override
- public void write(byte[] b, int off, int len) throws IOException {
- zipStream.write(b, off, len);
- }
- @Override
- public void write(byte[] b) throws IOException {
- zipStream.write(b);
- }
- @Override
- public void write(int arg0) throws IOException {
- zipStream.write(arg0);
- }
- public void finish() throws IOException {
- zipStream.finish();
- }
- public void close() throws IOException {
- zipStream.close();
- }
- }
GZipResponse.java
- import java.io.IOException;
- import java.io.OutputStreamWriter;
- import java.io.PrintWriter;
- import javax.servlet.ServletOutputStream;
- import javax.servlet.http.HttpServletResponse;
- import javax.servlet.http.HttpServletResponseWrapper;
- public class GZipResponse extends HttpServletResponseWrapper {
- private GZipStream stream;
- private PrintWriter writer;
- public GZipResponse(HttpServletResponse response) throws IOException{
- super(response);
- stream=new GZipStream(response.getOutputStream());
- }
- @Override
- public ServletOutputStream getOutputStream() throws IOException {
- return stream;
- }
- @Override
- public PrintWriter getWriter() throws IOException {
- if (writer == null) {
- writer = new PrintWriter(new OutputStreamWriter(
- getOutputStream(), getCharacterEncoding()));
- }
- return writer;
- }
- public void flush() throws IOException {
- if (writer != null) {
- writer.flush();
- }
- stream.finish();
- }
- }
GZipFilter.java
- import java.io.IOException;
- 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.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- public class GZipFilter implements Filter {
- public void destroy() {
- }
- public void init(FilterConfig fConfig) throws ServletException {
- }
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
- throws IOException, ServletException {
- HttpServletRequest req=(HttpServletRequest)request;
- HttpServletResponse res=(HttpServletResponse)response;
- if(isGZipEncoding(req)){
- GZipResponse zipResponse=new GZipResponse(res);
- res.setHeader("Content-Encoding", "gzip");
- chain.doFilter(request, zipResponse);
- zipResponse.flush();
- } else {
- chain.doFilter(request, response);
- }
- }
- /**
- * 判断浏览器是否支持GZIP
- * @param request
- * @return
- */
- private static boolean isGZipEncoding(HttpServletRequest request){
- boolean flag=false;
- String encoding=request.getHeader("Accept-Encoding");
- ){
- flag=true;
- }
- return flag;
- }
- }
web.xml配置
- <filter>
- <description>
- </description>
- <display-name>GZipFilter</display-name>
- <filter-name>GZipFilter</filter-name>
- <filter-class>GZipFilter</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>GZipFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
这个配置是对所有的资源都进行压缩传输,对于图片,flash等本身已经压缩过的文件就没有必要再进行压缩了,可以根据自己的需要更改<url-pattern>已提高WEB访问速度。
tomcat自带源码剖析:
url:http://hi.baidu.com/springfieldx/blog/item/9faa88dfd5760414495403b6.html
在响应请求的时候对response进行封装,替换他的输出流为 GZipOutputStream 压缩输出流
- package compressionFilters;
- import java.io.IOException;
- import java.util.zip.GZIPOutputStream;
- import javax.servlet.ServletOutputStream;
- import javax.servlet.http.HttpServletResponse;
- public class CompressionResponseStream extends ServletOutputStream {
- //是否启用压缩的临界值
- ;
- //临时容纳写入的数据缓冲区
- protected byte[] buffer = null;
- //缓冲区实际写入的数据量
- ;
- protected GZIPOutputStream gzipstream = null;
- //当前流对象是否处于关闭状态
- protected boolean closed = false;
- ;
- //用于返回数据的 Response对象
- protected HttpServletResponse response = null;
- protected ServletOutputStream output = null;
- public CompressionResponseStream(HttpServletResponse response) throws IOException{
- super();
- closed = false;
- this.response = response;
- this.output = response.getOutputStream();
- }
- //设置启用压缩的临界值,并初始化输出缓冲区
- public void setBuffer(int threshold){
- compressThreshold = threshold;
- buffer = new byte[threshold];
- }
- /**
- * 关闭流对象
- */
- public void close() throws IOException{
- if(closed){
- throw new IOException("This output stream has already been closed");
- }
- //如果当前启用的是压缩流,用压缩流刷新缓冲区
- if(gzipstream != null){
- flushToGZip();
- gzipstream.close();
- gzipstream = null;
- }else{
- //如果未开启压缩,则用response的默认输出流刷新缓冲区
- ){
- , bufferCount);
- ;
- }
- }
- }
- /**
- * 刷新输出缓冲区
- */
- public void flush() throws IOException{
- if(closed){
- throw new IOException("Cannot flush a closed output stream");
- }
- if(gzipstream != null){
- gzipstream.flush();
- }
- }
- public void write(int b) throws IOException {
- if(closed){
- throw new IOException("Cannot write to a closed output stream");
- }
- //如果数据超出了缓冲区(启用压缩的临界值),则启用压缩模式
- if(bufferCount >= buffer.length){
- flushToGZip();
- }
- //如果没有超出缓冲区,则将数据写入缓冲区
- buffer[bufferCount++] = (byte)b;
- }
- public void write(byte[] b,int off,int len) throws IOException{
- if(closed){
- throw new IOException("Cannot write to a closed output stream");
- }
- ){
- return;
- }
- //如果缓冲区能容纳这些数据则写入缓冲区
- if(len <= buffer.length - bufferCount){
- System.arraycopy(b, off, buffer, bufferCount, len);
- bufferCount += len;
- return;
- }
- //如果缓冲区剩余空间不住足,则开启压缩流对象
- flushToGZip();
- //如果清空后的缓冲区能够容纳传送过来的数据,则将数据写入缓冲区
- if(len <= buffer.length - bufferCount){
- System.arraycopy(b, off, buffer, bufferCount, len);
- bufferCount += len;
- return;
- }
- //如果缓冲区不能容纳传送进来的数据,则直接将数据写入压缩流对象
- writeToGZip(b, off, len);
- }
- //刷新压缩流对象的缓冲区
- public void flushToGZip() throws IOException{
- ){
- , bufferCount);
- ;
- }
- }
- public void writeToGZip(byte b[],int off,int len)throws IOException{
- //如果压缩流对象为空,这里初始化它
- if(gzipstream == null){
- response.addHeader("Content-Encoding", "gzip");
- gzipstream = new GZIPOutputStream(output);
- }
- //将数据听过压缩流对象输出到response的输出流
- gzipstream.write(b,off,len);
- }
- public boolean closed(){
- return closed;
- }
- }
- package compressionFilters;
- import java.io.IOException;
- import java.util.zip.GZIPOutputStream;
- import javax.servlet.ServletOutputStream;
- import javax.servlet.http.HttpServletResponse;
- public class CompressionResponseStream extends ServletOutputStream {
- //是否启用压缩的临界值
- ;
- //临时容纳写入的数据缓冲区
- protected byte[] buffer = null;
- //缓冲区实际写入的数据量
- ;
- protected GZIPOutputStream gzipstream = null;
- //当前流对象是否处于关闭状态
- protected boolean closed = false;
- ;
- //用于返回数据的 Response对象
- protected HttpServletResponse response = null;
- protected ServletOutputStream output = null;
- public CompressionResponseStream(HttpServletResponse response) throws IOException{
- super();
- closed = false;
- this.response = response;
- this.output = response.getOutputStream();
- }
- //设置启用压缩的临界值,并初始化输出缓冲区
- public void setBuffer(int threshold){
- compressThreshold = threshold;
- buffer = new byte[threshold];
- }
- /**
- * 关闭流对象
- */
- public void close() throws IOException{
- if(closed){
- throw new IOException("This output stream has already been closed");
- }
- //如果当前启用的是压缩流,用压缩流刷新缓冲区
- if(gzipstream != null){
- flushToGZip();
- gzipstream.close();
- gzipstream = null;
- }else{
- //如果未开启压缩,则用response的默认输出流刷新缓冲区
- ){
- , bufferCount);
- ;
- }
- }
- }
- /**
- * 刷新输出缓冲区
- */
- public void flush() throws IOException{
- if(closed){
- throw new IOException("Cannot flush a closed output stream");
- }
- if(gzipstream != null){
- gzipstream.flush();
- }
- }
- public void write(int b) throws IOException {
- if(closed){
- throw new IOException("Cannot write to a closed output stream");
- }
- //如果数据超出了缓冲区(启用压缩的临界值),则启用压缩模式
- if(bufferCount >= buffer.length){
- flushToGZip();
- }
- //如果没有超出缓冲区,则将数据写入缓冲区
- buffer[bufferCount++] = (byte)b;
- }
- public void write(byte[] b,int off,int len) throws IOException{
- if(closed){
- throw new IOException("Cannot write to a closed output stream");
- }
- ){
- return;
- }
- //如果缓冲区能容纳这些数据则写入缓冲区
- if(len <= buffer.length - bufferCount){
- System.arraycopy(b, off, buffer, bufferCount, len);
- bufferCount += len;
- return;
- }
- //如果缓冲区剩余空间不住足,则开启压缩流对象
- flushToGZip();
- //如果清空后的缓冲区能够容纳传送过来的数据,则将数据写入缓冲区
- if(len <= buffer.length - bufferCount){
- System.arraycopy(b, off, buffer, bufferCount, len);
- bufferCount += len;
- return;
- }
- //如果缓冲区不能容纳传送进来的数据,则直接将数据写入压缩流对象
- writeToGZip(b, off, len);
- }
- //刷新压缩流对象的缓冲区
- public void flushToGZip() throws IOException{
- ){
- , bufferCount);
- ;
- }
- }
- public void writeToGZip(byte b[],int off,int len)throws IOException{
- //如果压缩流对象为空,这里初始化它
- if(gzipstream == null){
- response.addHeader("Content-Encoding", "gzip");
- gzipstream = new GZIPOutputStream(output);
- }
- //将数据听过压缩流对象输出到response的输出流
- gzipstream.write(b,off,len);
- }
- public boolean closed(){
- return closed;
- }
- }
- package compressionFilters;
- import java.io.IOException;
- import java.io.OutputStream;
- import java.io.OutputStreamWriter;
- import java.io.PrintWriter;
- import javax.servlet.ServletOutputStream;
- import javax.servlet.http.HttpServletResponse;
- import javax.servlet.http.HttpServletResponseWrapper;
- public class CompressionServletResponseWrapper extends
- HttpServletResponseWrapper {
- /**
- * 原始的response对象
- */
- protected HttpServletResponse origResponse = null;
- protected static final String info = "CompressionServletResponseWrapper";
- /**
- * response对象的输出流
- */
- protected ServletOutputStream stream = null;
- /**
- * response
- */
- protected PrintWriter writer = null;
- ;
- protected String contentType = null;
- public CompressionServletResponseWrapper(HttpServletResponse response) {
- super(response);
- origResponse = response;
- }
- /**
- * 设置实体类型
- */
- public void setContentType(String contentType){
- this.contentType = contentType;
- origResponse.setContentType(contentType);
- }
- /**
- * 设置启用压缩的临界值
- * @param threshold 临界值
- */
- public void setCompressionThreshold(int threshold){
- this.threshold = threshold;
- }
- public ServletOutputStream createOutputStream() throws IOException{
- CompressionResponseStream stream = new CompressionResponseStream(origResponse);
- stream.setBuffer(threshold);
- return stream;
- }
- //关闭输出对象
- public void finishResponse(){
- try {
- if(writer != null){
- writer.close();
- }else{
- if(stream != null){
- stream.close();
- }
- }
- } catch (IOException e) {
- }
- }
- public void flushBuffer() throws IOException{
- ((CompressionResponseStream)stream).flush();
- }
- public ServletOutputStream getOutputStream() throws IOException{
- //如果字符流打开,则抛出异常
- if(writer != null)
- throw new IllegalStateException("getWriter() has already been called for this response");
- if(stream == null) stream = createOutputStream();
- return stream;
- }
- public PrintWriter getWriter() throws IOException{
- if(writer != null){
- return (writer);
- }
- if(stream != null)
- throw new IllegalStateException("getOutputStream() has already been called for this response");
- stream = createOutputStream();
- String charEnc = origResponse.getCharacterEncoding();
- if(charEnc != null){
- writer = new PrintWriter(new OutputStreamWriter(stream,charEnc));
- }else{
- writer = new PrintWriter(stream);
- }
- return writer;
- }
- private static String getCharsetFromContentType(String type){
- if(type == null){
- return null;
- }
- int semi = type.indexOf(":");
- ){
- return null;
- }
- );
- int charsetLocation = afterSemi.indexOf("charset=");
- ){
- return null;
- }else{
- );
- String encoding = afterCharset.trim();
- return encoding;
- }
- }
- }
reference:
1.http://onjava.com/pub/a/onjava/2003/11/19/filters.html
2.java filter 过滤机制详解 http://hi.baidu.com/linfengtingyu1/blog/item/e14a1af20de0505b352accda.html
3.java.servlet.Filter的应用http://yuhaining.spaces.live.com/Blog/cns!5BBD70DF0F6F839C!307.entry
4.使用filter机制来GZIP压缩网页http://www.javamilk.cn/article/notes/624.htm
JSP Filter,GZIP压缩响应流的更多相关文章
- thttpd增加gzip压缩响应报文体功能,以减少传输数据量
thttpd thttpd是一个非常小巧的轻量级web server,它非常非常简单,仅仅提供了HTTP/1.1和简单的CGI支持,在其官方网站上有一个与其他web server(如Apache, Z ...
- Android GZIP压缩IO流,优化APP数据传输(一)
我是小搬运工,今天讲解流的压缩传输 在我们安卓开发中,通常伴随着大量的数据传输,在此,楼主给出一个简单的压缩流的数据进行操作. public void GZIPCpf(String path) { / ...
- Springboot 之 Filter 实现超大响应 JSON 数据压缩
简介 项目中,请求时发送超大 json 数据外:响应时也有可能返回超大 json数据.上一篇实现了请求数据的 gzip 压缩.本篇通过 filter 实现对响应 json 数据的压缩. 先了解一下以下 ...
- 使用filter过滤GZIP压缩(二)
在代码之前,讲一下用filter实现GZIP压缩的原理: 因为GZIP压缩之后,是从服务器端传输到浏览器端,从servlet到浏览器(从jsp到浏览器),其实是response带回内容,所以我们要在f ...
- Java Web 减少网络 IO、静态资源磁盘 IO 有效的办法--响应使用 GZIP( 压缩http请求与响应gzip压缩)
(转载http://blog.csdn.net/hylclxy/article/details/7779662) 出于节约流量考虑, 客户端在向服务端发送request的时候对post数据进行gzip ...
- Springboot 之 Filter 实现 Gzip 压缩超大 json 对象
简介 在项目中,存在传递超大 json 数据的场景.直接传输超大 json 数据的话,有以下两个弊端 占用网络带宽,而有些云产品就是按照带宽来计费的,间接浪费了钱 传输数据大导致网络传输耗时较长 为了 ...
- GZIP压缩优化
使用gzip优化web应用(filter实现) 相关知识: gzip是http协议中使用的一种加密算法,客户端向web服务器端发出了请求后,通常情况下服务器端会将页面文件和其他资源,返回到客户端,客户 ...
- 过滤器-->GZIP压缩
1.创建一个 可以使用GZIPOutputStream 压缩的流 package com.zh.yasuo2; import java.io.IOException; import java.util ...
- GZIP压缩提高网络传输效率
[spring]通过GZIP压缩提高网络传输效率(可以实现任何资源的gzip压缩.包括AJAX) gzip是http协议中使用的一种加密算法,客户端向web服务器端发出了请求后,通常情况下服务器端会将 ...
随机推荐
- export
export export PATH=$PATH:/ROOT
- 使用PHP flush 函数的时候我们需要注意些什么呢?
WebServer(可以认为特指apache)的缓冲区.在apache module的sapi下, flush会通过调用sapi_module的flush成员函数指针,间接的调用apache的api: ...
- Linux用户组与用户组进阶命令
1.用户锁定 : passwd -l user1 2.解除用户锁定:passwd -u user1 3.用户无密码登记:passwd -d user1 4.添加到附属用户组:gpasswd -a us ...
- http://www.cnblogs.com/xqin/p/4862849.html
一.前言 半年前左右折腾了一个前后端分离的架子,这几天才想起来翻出来分享给大家.关于前后端分离这个话题大家也谈了很久了,希望我这个实践能对大家有点点帮助,演示和源码都贴在后面. 二.技术架构 这两年a ...
- js获取页面高度赋值给div
<script type="text/javascript"> window.onload=function(){ map_width=document.body.cl ...
- Java总结反射
[案例1]通过一个对象获得完整的包名和类名 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package Reflect; /** * 通过一个对象获得完整的包名和类名 ...
- anroid打包
http://blog.csdn.net/qq435757399/article/details/46634363 转载 Gradle打包APP签名 默认情况下,debug被配置成使用一个debug ...
- POJ 3061 Subsequence 尺取法
转自博客:http://blog.chinaunix.net/uid-24922718-id-4848418.html 尺取法就是两个指针表示区间[l,r]的开始与结束 然后根据题目来将端点移动,是一 ...
- UIActionSheet 这样写为什么显示为空白 ???
func pickePhotoFromSheet() { var sheet:UIActionSheet = UIActionSheet() var button = UIButton.button ...
- 修改ftp密码
1.运行cmd2.在DOS窗口中输入FTP 127.0.0.13.出现用户名输入提示“user”,键入用户名,按回车4.出现输入密码提示:“Password”,键入密码后按回车登录到服务器中5.在ft ...