全部博文(2065)
分类: Java
2010-02-07 13:21:06
jsp实现GZIP压缩输出过滤器
目前实现gzip压缩有2种办法:
一、是有的容器(服务器)提供的功能,但这个局限于特定容器。比如apache+tomcat或者resin-pro版。
二、是部署前手动gzip压缩,配合servlet过滤器使用,这个能实现gzip功能,但是降低了灵活性。
一、
介绍Resin容器中配置GZIP压缩方法
http://localhost:8080/MyProj/pdf/0.jpg 可以打开一张图片。用Httpwatch查看
Accept-Encoding: gzip, deflate
Sent
: 315
Received
43106
开始配置Resin
我按照这样的配置:
再测试发现不起作用!不清楚如何配置哦!
我再看了一下资料上面有讲说 需要resin的专业版即resin-pro
现在再看下我的resin :Resin-
果然是我的版本不一致导致的。重新从网上下载一下专业版的RESIN下来再试!
以下是我再测试的过程:
测试发现还是不行呀!我昏~~~ 不过感觉专业版与普通版在配置上面还是有点差别的
待续未完!
二、
通过程序实现
采用gzip servlet filter实现
从 HTTP/1.1 开始,客户端就可以在请求头中添加
Accept-Encoding: gzip,deflate (可以从HTTP WATCH中查看发现确实支持)
来向请求的服务器表明自己支持 Gzip 压缩的响应。Web 服务器则在响应头中添加
Content-Encoding: gzip
来向客户端表明响应体是经过 gzip 压缩的。
程序代码如下:
(在此非常感谢 http://tdcq.javaeye.com/blog/453644
提供代码)
具体代码如下:
package sh.blog.util.web.filter;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;
import javax.servlet.ServletOutputStream;
public class CompressedStream extends ServletOutputStream {
private ServletOutputStream
out;
private GZIPOutputStream gzip;
/**
* 指定压缩缓冲流
* @param 输出流到压缩
* @throws IOException if an error occurs with the {@link GZIPOutputStream}.
*/
public
CompressedStream(ServletOutputStream out) throws IOException {
this.out = out;
reset();
}
/** @see ServletOutputStream * */
public void close() throws IOException {
gzip.close();
}
/** @see ServletOutputStream * */
public void flush() throws IOException {
gzip.flush();
}
/** @see ServletOutputStream * */
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
/** @see ServletOutputStream * */
public void write(byte[] b, int off, int len) throws IOException {
gzip.write(b, off, len);
}
/** @see ServletOutputStream * */
public void write(int b) throws IOException {
gzip.write(b);
}
public void reset() throws IOException {
gzip = new GZIPOutputStream(out);
}
}
package sh.blog.util.web.filter;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
public class CompressionResponse extends HttpServletResponseWrapper{
protected HttpServletResponse response;
private ServletOutputStream out;
private CompressedStream compressedOut;
private PrintWriter writer;
protected int contentLength;
public CompressionResponse(HttpServletResponse response) throws IOException {
super(response);
this.response = response;
compressedOut = new CompressedStream(response.getOutputStream());
}
public void setContentLength(int len) {
contentLength = len;
}
public ServletOutputStream getOutputStream() throws IOException {
if (null == out) {
if (null != writer) {
throw new IllegalStateException("getWriter() has already been called on this response.");
}
out = compressedOut;
}
return out;
}
public PrintWriter getWriter() throws IOException {
if (null == writer) {
if (null != out) {
throw new IllegalStateException("getOutputStream() has already been called on this response.");
}
writer = new PrintWriter(compressedOut);
}
return writer;
}
public void flushBuffer() {
try {
if (writer != null) {
writer.flush();
}else if (out != null) {
out.flush();
}
}catch (IOException e) {
e.printStackTrace();
}
}
public void reset() {
super.reset();
try {
compressedOut.reset();
}catch (IOException e) {
throw new RuntimeException(e);
}
}
public void resetBuffer() {
super.resetBuffer();
try {
compressedOut.reset();
}catch (IOException e) {
throw new RuntimeException(e);
}
}
public void close() throws IOException {
compressedOut.close();
}
}
package sh.blog.util.web.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;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class CompressionFilter implements Filter {
protected Log log = LogFactory.getFactory().getInstance(this.getClass().getName());
@SuppressWarnings("unchecked")
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException,
ServletException {
boolean compress = false;
if (request instanceof HttpServletRequest){
HttpServletRequest httpRequest =
(HttpServletRequest) request;
Enumeration headers =
httpRequest.getHeaders("Accept-Encoding");
while (headers.hasMoreElements()){
String value = (String)
headers.nextElement();
if (value.indexOf("gzip") != -1){
compress = true;
}
}
}
if (compress){//如果浏览器支持则压缩
HttpServletResponse httpResponse =
(HttpServletResponse) response;
httpResponse.addHeader("Content-Encoding", "gzip");
CompressionResponse compressionResponse= new
CompressionResponse(httpResponse);
chain.doFilter(request, compressionResponse);
compressionResponse.close();
}
else{//如果浏览器不支持则不压缩
chain.doFilter(request,
response);
}
}
public void init(FilterConfig config) throws ServletException
{
}
public void destroy(){
}
}
一共有三个CLASS文件!实现GZIP压缩输出响应
2.1 对图片输出做压缩处理测试
建立目录pdf里面存储图片
第一步:不配置过滤器用HTTP WATCHE发现
image/jpeg : 42891 bytes, 670 x 446 pixels
第二步:配置Web.xml配置过滤器
<filter>
<filter-name>gzipfilter-name>
<filter-class>sh.blog.util.web.filter.CompressionFilterfilter-class>
filter>
<filter-mapping>
<filter-name>gzipfilter-name>
<url-pattern>/pdf/*url-pattern>
filter-mapping>
再用HTTP WATCH查看发现
image/jpeg : 42891 bytes, gzip compressed to 42712 bytes ( 0.417 %
saving ), 670 x 446 pixels
实现了一次压缩处理输出!
PS:我再用png格式的图片做过一次测试发现一次可以实现GZIP压缩输出
结论:通过上面的过滤器能够实现对图片的压缩处理,提高响应速度!
2.2 对音乐的压缩处理以MP3的输出 为测试对象
建立目录music里面存储音乐
第一步:不配置过滤器发现
audio/mpeg : 9001 bytes of binary data
第二步:配置过滤器
<filter>
<filter-name>gzipfilter-name>
<filter-class>sh.blog.util.web.filter.CompressionFilterfilter-class>
filter>
<filter-mapping>
<filter-name>gzipfilter-name>
<url-pattern>/music/*url-pattern>
filter-mapping>
再次查看发现:
audio/mpeg : , gzip compressed to 0 bytes ( 0 % saving )
结论:上面的算法对音乐文件不起压缩作用。感觉这种GZIP的算法应该是不同的格式算法不一样
2.3 对JS文件压缩输出
第一步:不做压缩
4864
第二步:配置压缩
<filter>
<filter-name>gzipfilter-name>
<filter-class>sh.blog.util.web.filter.CompressionFilterfilter-class>
filter>
<filter-mapping>
<filter-name>gzipfilter-name>
<url-pattern>/scripts/*.jsurl-pattern>
filter-mapping>
输出:
application/x-javascript : 4636 bytes, gzip compressed to
69 bytes ( 98.5 % saving )
查看发现JS的压缩是相当高的了!
结论:将JS存入指定的目录然后直接对此目录做GZIP压缩输出。可以看到效果是显著的!
通过做GZIP压缩输出之后可以减少网络带宽流量从而加快下载速度!
2.4 对CSS文件压缩输出
第一步:没有压缩输出
text/css : 413 bytes
第二步:压缩
配置:
<filter>
<filter-name>gzipfilter-name>
<filter-class>sh.blog.util.web.filter.CompressionFilterfilter-class>
filter>
<filter-mapping>
<filter-name>gzipfilter-name>
<url-pattern>/scripts/*.jsurl-pattern>
<url-pattern>/style/*.cssurl-pattern>
filter-mapping>
结果:
text/css : 413 bytes, gzip compressed to 101 bytes ( 75.5
% saving )
结论:对CSS的压缩效果也是非常明显的哦!
2.5 对HTML页面压缩输出
第一步:不压缩
text/html : 2272 bytes
第二步;压缩
<filter>
<filter-name>gzipfilter-name>
<filter-class>sh.blog.util.web.filter.CompressionFilterfilter-class>
filter>
<filter-mapping>
<filter-name>gzipfilter-name>
<url-pattern>/scripts/*.jsurl-pattern>
<url-pattern>/style/*.cssurl-pattern>
<url-pattern>*.htmlurl-pattern>
filter-mapping>
结果:
text/html : 2272 bytes, gzip compressed to 240 bytes (
89.4 % saving )
结论:对HTML的压缩效果也是非常明显的哦!
2.6 对JSP页面的压缩
第一步:未做压缩
text/html; charset=iso-8859-1 : 1008 bytes
第二步:压缩输出
<filter>
<filter-name>gzipfilter-name>
<filter-class>sh.blog.util.web.filter.CompressionFilterfilter-class>
filter>
<filter-mapping>
<filter-name>gzipfilter-name>
<url-pattern>/scripts/*.jsurl-pattern>
<url-pattern>/style/*.cssurl-pattern>
<url-pattern>*.htmlurl-pattern>
<url-pattern>*.jspurl-pattern>
filter-mapping>
结果:页面 无输出!
结论:
以上的算法可以应用于 图片、HTML、CSS、JS的GZIP压缩输出。对于JSP页面无效!
应用:
将来可以在站点中编写此类过滤器,将页面内容尽可能地做GZIP输出提高下载的速度!