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