`
_Yggd
  • 浏览: 89900 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

servlet 实现过滤器中向浏览器发送压缩数据流

阅读更多
参考:http://fengyanzhang.iteye.com/admin/blogs/1853733

在如上博文的过滤器中,向浏览器发送压缩数据流失败,先给出正确的数据压缩功能的过滤器:

web.xml:

    <filter>
<filter-name>CompressionFilter</filter-name>
<filter-class>com.fyz.filter.CompressionFilter</filter-class>
<init-param>
    <param-name>compressionThreshold</param-name>
    <param-value>100</param-value>
</init-param>
<init-param>
    <param-name>debug</param-name>
    <param-value>10</param-value>
</init-param>
    </filter>
    <filter-mapping>
<filter-name>CompressionFilter</filter-name>
<url-pattern>/*</url-pattern>
    </filter-mapping>



具体的过滤器:


package com.fyz.filter;

import java.io.IOException;
import java.util.Enumeration;
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 CompressionFilter implements Filter {

    private FilterConfig config = null;
    private int minThreshold = 128;
    protected int compressionThreshold;  //压缩极限
    private int debug = 0;

    public void init(FilterConfig filterConfig) {  //初始化代码,得到初始化的值

config = filterConfig;
if (filterConfig != null) {
    String value = filterConfig.getInitParameter("debug");

    if (value != null) {
debug = Integer.parseInt(value);
    } else {
debug = 0;
    }

    String str = filterConfig.getInitParameter("compressionThreshold");
    if (str != null) {
compressionThreshold = Integer.parseInt(str);
if (compressionThreshold != 0 && compressionThreshold < minThreshold) {
    if (debug > 0) {
System.out.println("compressionThreshold should be either 0 - no compression or >= " + minThreshold);
System.out.println("compressionThreshold set to " + minThreshold);
    }
    compressionThreshold = minThreshold;
}
    } else {
compressionThreshold = 0;
    }

} else {
    compressionThreshold = 0;
}

    }

    public void destroy() {

this.config = null;

    }

    public void doFilter(ServletRequest request, ServletResponse response,
    FilterChain chain) throws IOException, ServletException {
if (debug > 0) {
    System.out.println("@doFilter");
}

if (compressionThreshold == 0) {
    if (debug > 0) {
System.out.println("doFilter gets called, but compressionTreshold is set to 0 - no compression");
    }
    chain.doFilter(request, response);
    return;
}

boolean supportCompression = false;
if (request instanceof HttpServletRequest) {
    if (debug > 1) {
System.out.println("requestURI = " + ((HttpServletRequest) request).getRequestURI());
    }

    // Are we allowed to compress ?
    String s = (String) ((HttpServletRequest) request).getParameter("gzip");
    if ("false".equals(s)) {
if (debug > 0) {
    System.out.println("got parameter gzip=false --> don't compress, just chain filter");
}
chain.doFilter(request, response);
return;
    }

    Enumeration e =
    ((HttpServletRequest) request).getHeaders("Accept-Encoding");
    while (e.hasMoreElements()) {
String name = (String) e.nextElement();
if (name.indexOf("gzip") != -1) {
    if (debug > 0) {
System.out.println("supports compression");
    }
    supportCompression = true;
} else {
    if (debug > 0) {
System.out.println("no support for compresion");
    }
}
    }
}

if (!supportCompression) {
    if (debug > 0) {
System.out.println("doFilter gets called wo compression");
    }
    chain.doFilter(request, response);
    return;
} else {
    if (response instanceof HttpServletResponse) {
CompressionServletResponseWrapper wrappedResponse =
new CompressionServletResponseWrapper((HttpServletResponse) response);
wrappedResponse.setDebugLevel(debug);
wrappedResponse.setCompressionThreshold(compressionThreshold);
if (debug > 0) {
    System.out.println("doFilter gets called with compression");
}
try {
    chain.doFilter(request, wrappedResponse);
} finally {
    wrappedResponse.finishResponse();
}
return;
    }
}
    }

    public void setFilterConfig(FilterConfig filterConfig) {
init(filterConfig);
    }

    public FilterConfig getFilterConfig() {
return config;
    }
}

重构response:


package compressionFilters;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Locale;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletResponse;
import javax.servlet.ServletResponseWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

/**
* Implementation of <b>HttpServletResponseWrapper</b> that works with
* the CompressionServletResponseStream implementation..
*
* @author Amy Roh
* @author Dmitri Valdin
* @version $Revision$, $Date$
*/

public class CompressionServletResponseWrapper extends HttpServletResponseWrapper {
   
    protected HttpServletResponse origResponse = null;
   
    public CompressionServletResponseWrapper(HttpServletResponse response) {
        super(response);
        origResponse = response;
        if (debug > 1) {
            System.out.println("CompressionServletResponseWrapper constructor gets called");
        }
    }

    protected static final String info = "CompressionServletResponseWrapper";

    /**
     * The ServletOutputStream that has been returned by
     * <code>getOutputStream()</code>, if any.
     */

    protected ServletOutputStream stream = null;


    /**
     * The PrintWriter that has been returned by
     * <code>getWriter()</code>, if any.
     */

    protected PrintWriter writer = null;

    /**
     * The threshold number to compress
     */
    protected int threshold = 0;

    /**
     * Debug level
     */
    private int debug = 0;

    /**
     * Content type
     */
    protected String contentType = null;

    // --------------------------------------------------------- Public Methods


    /**
     * Set content type
     */
    public void setContentType(String contentType) {
        if (debug > 1) {
            System.out.println("setContentType to "+contentType);
        }
        this.contentType = contentType;
        origResponse.setContentType(contentType);
    }


    /**
     * Set threshold number
     */
    public void setCompressionThreshold(int threshold) {
        if (debug > 1) {
            System.out.println("setCompressionThreshold to " + threshold);
        }
        this.threshold = threshold;
    }


    /**
     * Set debug level
     */
    public void setDebugLevel(int debug) {
        this.debug = debug;
    }


    /**
     * Create and return a ServletOutputStream to write the content
     * associated with this Response.
     *
     * @exception IOException if an input/output error occurs
     */
    public ServletOutputStream createOutputStream() throws IOException {
        if (debug > 1) {
            System.out.println("createOutputStream gets called");
        }

        CompressionResponseStream stream = new CompressionResponseStream(origResponse);
        stream.setDebugLevel(debug);
        stream.setBuffer(threshold);

        return stream;

    }


    /**
     * Finish a response.
     */
    public void finishResponse() {
        try {
            if (writer != null) {
                writer.close();
            } else {
                if (stream != null)
                    stream.close();
            }
        } catch (IOException e) {
        }
    }


    // ------------------------------------------------ ServletResponse Methods


    /**
     * Flush the buffer and commit this response.
     *
     * @exception IOException if an input/output error occurs
     */
    public void flushBuffer() throws IOException {
        if (debug > 1) {
            System.out.println("flush buffer @ CompressionServletResponseWrapper");
        }
        ((CompressionResponseStream)stream).flush();

    }

    /**
     * Return the servlet output stream associated with this Response.
     *
     * @exception IllegalStateException if <code>getWriter</code> has
     *  already been called for this response
     * @exception IOException if an input/output error occurs
     */
    public ServletOutputStream getOutputStream() throws IOException {

        if (writer != null)
            throw new IllegalStateException("getWriter() has already been called for this response");

        if (stream == null)
            stream = createOutputStream();
        if (debug > 1) {
            System.out.println("stream is set to "+stream+" in getOutputStream");
        }

        return (stream);

    }

    /**
     * Return the writer associated with this Response.
     *
     * @exception IllegalStateException if <code>getOutputStream</code> has
     *  already been called for this response
     * @exception IOException if an input/output error occurs
     */
    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();
        if (debug > 1) {
            System.out.println("stream is set to "+stream+" in getWriter");
        }
        //String charset = getCharsetFromContentType(contentType);
        String charEnc = origResponse.getCharacterEncoding();
        if (debug > 1) {
            System.out.println("character encoding is " + charEnc);
        }
        // HttpServletResponse.getCharacterEncoding() shouldn't return null
        // according the spec, so feel free to remove that "if"
        if (charEnc != null) {
            writer = new PrintWriter(new OutputStreamWriter(stream, charEnc));
        } else {
            writer = new PrintWriter(stream);
        }
       
        return (writer);

    }


    public void setContentLength(int length) {
    }


    /**
     * Returns character from content type. This method was taken from tomcat.
     * @author rajo
     */
    private static String getCharsetFromContentType(String type) {

        if (type == null) {
            return null;
        }
        int semi = type.indexOf(";");
        if (semi == -1) {
            return null;
        }
        String afterSemi = type.substring(semi + 1);
        int charsetLocation = afterSemi.indexOf("charset=");
        if(charsetLocation == -1) {
            return null;
        } else {
            String afterCharset = afterSemi.substring(charsetLocation +;
            String encoding = afterCharset.trim();
            return encoding;
        }
    }

}



输出流:


package com.fyz.filter;

import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.GZIPOutputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

/**
* Implementation of <b>ServletOutputStream</b> that works with the
* CompressionServletResponseWrapper implementation.
*
* @author Amy Roh
* @author Dmitri Valdin
* @version $Revision$, $Date$
*/
public class CompressionResponseStream
extends ServletOutputStream {

    public CompressionResponseStream(HttpServletResponse response) throws IOException {

super();
closed = false;
this.response = response;
this.output = response.getOutputStream();

    }
    protected int compressionThreshold = 0;
    private int debug = 0;
    protected byte[] buffer = null; //输出字节缓冲
    protected int bufferCount = 0;
    protected GZIPOutputStream gzipstream = null;
    /**
     * Has this stream been closed?
     */
    protected boolean closed = false;
    /**
     * The content length past which we will not write, or -1 if there is no
     * defined content length.
     */
    protected int length = -1;
    /**
     * The response with which this servlet output stream is associated.
     */
    protected HttpServletResponse response = null;
    /**
     * The underlying servket output stream to which we should write data.
     */
    protected ServletOutputStream output = null;

    // --------------------------------------------------------- Public Methods
    /**
     * Set debug level
     */
    public void setDebugLevel(int debug) {
this.debug = debug;
    }

    /**
     * Set the compressionThreshold number and create buffer for this size
     */
    protected void setBuffer(int threshold) {
compressionThreshold = threshold;
buffer = new byte[compressionThreshold];
if (debug > 1) {
    System.out.println("buffer is set to " + compressionThreshold);
}
    }

    /**
     * Close this output stream, causing any buffered data to be flushed and any
     * further output data to throw an IOException.
     */
    @Override
    public void close() throws IOException {

if (debug > 1) {
    System.out.println("close() @ CompressionResponseStream");
}
if (closed) {
    throw new IOException("This output stream has already been closed");
}

if (gzipstream != null) {
    flushToGZip();
    gzipstream.close();
    gzipstream = null;
} else {
    if (bufferCount > 0) {
if (debug > 2) {
    System.out.print("output.write(");
    System.out.write(buffer, 0, bufferCount);
    System.out.println(")");
}
output.write(buffer, 0, bufferCount);
bufferCount = 0;
    }
}

output.close();
closed = true;

    }

    /**
     * Flush any buffered data for this output stream, which also causes the
     * response to be committed.
     */
    public void flush() throws IOException {

if (debug > 1) {
    System.out.println("flush() @ CompressionResponseStream");
}
if (closed) {
    throw new IOException("Cannot flush a closed output stream");
}

if (gzipstream != null) {
    gzipstream.flush();
}

    }

    public void flushToGZip() throws IOException {

if (debug > 1) {
    System.out.println("flushToGZip() @ CompressionResponseStream");
}
if (bufferCount > 0) {
    if (debug > 1) {
System.out.println("flushing out to GZipStream, bufferCount = " + bufferCount);
    }
    writeToGZip(buffer, 0, bufferCount);
    bufferCount = 0;
}

    }

    /**
     * Write the specified byte to our output stream.
     *
     * @param b The byte to be written
     *
     * @exception IOException if an input/output error occurs
     */
    public void write(int b) throws IOException {

if (debug > 1) {
    System.out.println("write " + b + " in CompressionResponseStream ");
}
if (closed) {
    throw new IOException("Cannot write to a closed output stream");
}

if (bufferCount >= buffer.length) {
    flushToGZip();
}

buffer[bufferCount++] = (byte) b;

    }

    /**
     * Write
     * <code>b.length</code> bytes from the specified byte array to our output
     * stream.
     *
     * @param b The byte array to be written
     *
     * @exception IOException if an input/output error occurs
     */
    public void write(byte b[]) throws IOException {

write(b, 0, b.length);

    }

    /**
     * Write
     * <code>len</code> bytes from the specified byte array, starting at the
     * specified offset, to our output stream.
     *
     * @param b The byte array containing the bytes to be written
     * @param off Zero-relative starting offset of the bytes to be written
     * @param len The number of bytes to be written
     *
     * @exception IOException if an input/output error occurs
     */
    public void write(byte b[], int off, int len) throws IOException {

if (debug > 1) {
    System.out.println("write, bufferCount = " + bufferCount + " len = " + len + " off = " + off);
}
if (debug > 2) {
    System.out.print("write(");
    System.out.write(b, off, len);
    System.out.println(")");
}

if (closed) {
    throw new IOException("Cannot write to a closed output stream");
}

if (len == 0) {
    return;
}

// Can we write into buffer ?
if (len <= (buffer.length - bufferCount)) {
    System.arraycopy(b, off, buffer, bufferCount, len);
    bufferCount += len;
    return;
}

// There is not enough space in buffer. Flush it ...
flushToGZip();

// ... and try again. Note, that bufferCount = 0 here !
if (len <= (buffer.length - bufferCount)) {
    System.arraycopy(b, off, buffer, bufferCount, len);
    bufferCount += len;
    return;
}

// write direct to gzip
writeToGZip(b, off, len);
    }

    public void writeToGZip(byte b[], int off, int len) throws IOException {

if (debug > 1) {
    System.out.println("writeToGZip, len = " + len);
}
if (debug > 2) {
    System.out.print("writeToGZip(");
    System.out.write(b, off, len);
    System.out.println(")");
}
if (gzipstream == null) {
    if (debug > 1) {
System.out.println("new GZIPOutputStream");
    }
    response.addHeader("Content-Encoding", "gzip");
    gzipstream = new GZIPOutputStream(output);
}
gzipstream.write(b, off, len);

    }

    // -------------------------------------------------------- Package Methods
    /**
     * Has this response stream been closed?
     */
    public boolean closed() {

return (this.closed);

    }
}

分享到:
评论

相关推荐

    Two Servlet Filters Every Web Application Should Have

    标题 "Two Servlet Filters Every Web Application Should Have" 指向的是在Web应用程序中使用Servlet过滤器来提升性能和效率的两个重要实践。Servlet过滤器是Java Servlet API的一部分,它们允许开发者在请求到达...

    web服务器三大组件servlet、Filter、Listener——浅浅笔记

    过滤器可以用来实现诸如认证、授权、日志记录、数据压缩等多种功能。在Filter中,我们可以添加业务逻辑判断,决定是否允许请求继续传递到目标资源。如果不满足特定条件,Filter可以阻止请求的进一步处理,提供了一种...

    Java--数据的压缩[借鉴].pdf

    过滤器会在Servlet处理请求之前和之后执行,所以可以在过滤器中实现GZIP压缩,这样无需修改每个Servlet的代码。 对于JSP页面,由于它们最终通过`JspWriter`输出,而`JspWriter`是`PrintWriter`的包装,可以考虑在`...

    用过滤器转换amr音频

    1. **Servlet过滤器**:Servlet过滤器是Java EE中的一种机制,它允许开发者在请求到达目标Servlet之前或者之后对请求/响应进行修改。在这里,过滤器可以拦截以".amr"结尾的URL请求,对它们进行特殊处理。 2. **音频...

    JavaWeb的Gzip

    Gzip在Web服务器和浏览器之间工作,当浏览器请求一个页面时,如果支持Gzip压缩,它会告诉服务器这个能力,服务器则会将内容压缩后再发送给浏览器,浏览器接收到压缩后的数据后进行解压,展示给用户。这一过程降低了...

    J2EE gzip压缩

    2. **过滤器(Filter)**:在Java应用中,我们也可以通过实现Servlet Filter来动态控制gzip压缩。创建一个实现了`javax.servlet.Filter`接口的类,然后在`doFilter`方法中检测请求和响应是否需要进行gzip处理。这种...

    JJEEGZIP学习资料

    4. **Servlet过滤器**:在Java EE环境中,开发者通常会创建一个`Filter`来自动处理HTTP请求和响应的GZIP压缩。这个过滤器会在发送响应之前对内容进行压缩,接收请求时解压缩数据。 5. **性能优化**:虽然GZIP能有效...

    学生选课系统项目文件(myeclipse 8.5版本)

    【描述】中提到的“有两个版本2017和8.5的区别就是过滤器”,这表明项目在不同版本的MyEclipse中存在差异,主要在于过滤器的处理方式。在2017版本中,可能已经解决了GET请求中的中文乱码问题,而在8.5版本中则需要...

    一个很好的论坛系统(jsp+mysql)

    1. `web.xml`:这是Web应用程序的部署描述符,定义了应用的配置信息,如Servlet的映射、过滤器、监听器等。 2. `classes`:这个目录存放的是编译后的Java类文件,包括论坛系统的核心业务逻辑、DAO(数据访问对象)层...

    uml.rar_java web server_web server client

    7. **过滤器(Filter)**:允许在请求到达目标Servlet之前进行预处理,或者在响应发送回客户端之后进行后处理。 8. **部署描述符(Deployment Descriptor, web.xml)**:配置Web应用程序的元数据。 压缩包中的“uml...

    基于J2EE的Ajax宝典

    - **Filter与Listener**:在Ajax应用中,过滤器和监听器可以用于处理请求前后的逻辑,如身份验证、日志记录等。 3. **Ajax框架** - **jQuery**:一个流行的JavaScript库,简化了Ajax操作,提供了易用的API。 - *...

    Professional Servlets and JSP The J2EE Web Tier

    过滤器是一种在请求处理链中拦截请求与响应的组件,用于执行预处理和后处理任务,比如安全检查、日志记录和数据压缩。而设计模式部分则介绍了在开发中应当遵循的成熟模式,如Struts框架的模式。 知识点三:异常处理...

    HttpServletRequest源码 HttpServletResponse源码

    在Java Web开发中,`HttpServletRequest`和`HttpServletResponse`是两个至关重要的接口,它们是Java Servlet API的核心组成部分,用于处理客户端(通常是Web浏览器)与服务器之间的HTTP通信。这两个接口提供了丰富的...

    JSP文件管理系统

    这可以通过实现Servlet过滤器或使用Spring Security等框架来实现。 6. 用户界面设计 使用HTML、CSS和JavaScript构建用户友好的界面,可能涉及AJAX技术实现异步操作,提高交互体验。 7. 性能优化 - 缓存策略:...

    新浪微博-java项目

    5. **配置文件**:如web.xml,用于配置Servlet和过滤器等。 6. **数据库脚本**:创建数据库表结构和初始数据。 7. **CSS和JavaScript文件**:负责页面样式和交互效果。 8. **图片和其他静态资源**:用于美化和增强...

    java开源包3

    GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以...

    java开源包4

    GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以...

    java 采用dwr框架构实现ajax

    1. **配置DWR**: 在Web应用的`web.xml`中添加DWR的Servlet配置,以及相应的过滤器和映射。 2. **创建Java接口和实现**: 定义一个Java接口,包含要暴露给JavaScript的方法,然后实现该接口。 3. **配置DWR Engine**: ...

    java开源包1

    GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以...

    java开源包11

    GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以...

Global site tag (gtag.js) - Google Analytics