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

3 篇文章 0 订阅
参考: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 + 8);
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);

}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值