Gzip Servlet Filter in Spring MVC

Posted By : Summy Saurav | 20-May-2014
In this blog I will explain how to use GZip servlet filter in Spring web application to speeds up the page load.
GZip servlet filter is used to compress JSP data (html,JS,CSS) and sent to browser , then browser will automatically decompresses it . This speeds up the page load compare to not compressed data sent to browser.
 
How it works:
Before rendering the jsp page, filter will be fetching browser properties via a header named as ACCEPT_ENCODING. So if the browser support the GZip encoding format , filter will wrap the servletResponse in our custom wrapper and send the wrapped response to browser and then browser will decompress it. If browser does not support Gzip encoding format then our filter will send the non wrapped response.
whenever a request is send to server GZip servlet filter wraps the HttpServletResponse and  override the getWritter() and getOutputStream() method of ServletResponse to write the compressed string on response.
 
Here is the Code
 
GZIPFilter.java
public class GZIPFilter implements Filter
{
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException 
	{
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		HttpServletResponse httpResponse = (HttpServletResponse) response;
		String acceptEncoding = httpRequest.getHeader(HttpHeaders.ACCEPT_ENCODING);
		if (acceptEncoding != null) 
		{
		 	System.out.println("Processing GZIPFilter");
			//searching for 'gzip' in ACCEPT_ENCODING header
		 	if (acceptEncoding.indexOf("gzip") >= 0) 
			{
                               GZIPResponseWrapper gzipResponse = new GZIPResponseWrapper(httpResponse);
				 chain.doFilter(request, gzipResponse);
				 gzipResponse.finish();
				 return; 
			}
         	}
         	chain.doFilter(request, response);
     	}
}
 
Now here is the code for ServletResponseWrapper which override the methods of ServletResponse to write the compressed response.
GZIPResponseWrapper.java
public class GZIPResponseWrapper extends HttpServletResponseWrapper 
{
	private GZIPResponseStream gzipStream;
	private ServletOutputStream outputStream;
	private PrintWriter printWriter;

	public GZIPResponseWrapper(HttpServletResponse response) throws IOException 
	{
		super(response);
		response.addHeader(HttpHeaders.CONTENT_ENCODING, "gzip");
	}

	public void finish() throws IOException 
	{
		if (printWriter != null)
		{
			printWriter.close();
		}
		if (outputStream != null) 
		{
			outputStream.close();
		}
		if (gzipStream != null) 
		{
			gzipStream.close();
		}
	}

	@Override
	public void flushBuffer() throws IOException 
	{
		if (printWriter != null) 
		{
			printWriter.flush();
		}
		if (outputStream != null) 
		{
			outputStream.flush();
		}
		super.flushBuffer();
	}

	@Override
	public ServletOutputStream getOutputStream() throws IOException 
	{
		if (printWriter != null) 
		{
			throw new IllegalStateException("printWriter already defined");
		}
		if (outputStream == null) 
		{
			initGzip();
			outputStream = gzipStream;
		}
		return outputStream;
	}

	@Override
	public PrintWriter getWriter() throws IOException 
	{
		if (outputStream != null) 
		{
			throw new IllegalStateException("printWriter already defined");
		}
		if (printWriter == null) 
		{
			initGzip();
			printWriter = new PrintWriter(new OutputStreamWriter(gzipStream, getResponse().getCharacterEncoding()));
		}
		System.out.println("GZIPFilter is Working fine!!!!!");
		return printWriter;
	}

	/* Creates a new output stream for writing compressed data in
	* the GZIP file format. */
	private void initGzip() throws IOException 
	{
		gzipStream = new GZIPResponseStream(getResponse().getOutputStream());
	}
}
 
GZIPResponseStream.java
public class GZIPResponseStream extends ServletOutputStream 
{
	GZIPOutputStream gzipStream;
	final AtomicBoolean open = new AtomicBoolean(true);
	OutputStream output;
	public GZIPResponseStream(OutputStream output) throws IOException 
	{
		this.output = output;
		gzipStream = new GZIPOutputStream(output);
	}
	@Override
	public void close() throws IOException 
	{
		if (open.compareAndSet(true, false)) 
		{
			gzipStream.close();
		}
	}
	@Override
	public void flush() throws IOException 
	{
		gzipStream.flush();
	}

	@Override
	public void write(byte b[]) throws IOException 
	{
		write(b, 0, b.length);
	}
	@Override
	public void write(byte b[], int off, int len) throws IOException 
	{
		if (!open.get()) 
		{
			throw new IOException("Stream closed!");
		}
		gzipStream.write(b, off, len);
	}
	@Override
	public void write(int b) throws IOException 
	{
		if (!open.get()) 
		{
			throw new IOException("Stream closed!");
		}
		gzipStream.write(b);
	}	
}
 
 
Thanks
Summy Saurav

About Author

Author Image
Summy Saurav

Summy is a kind of conscientious type of personality always be stable and practical in making decision; quick learner and problem solving attitude within a team . He is Fond of drawing,reading and computer programming

Request for Proposal

Name is required

Comment is required

Sending message..