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