通过过滤器Filter实现对响应内容gzip压缩示例代码

GZIP压缩过滤器

功能:对于web服务器响应给浏览器的数据进行gzip压缩返回,以减少数据量,提高服务器响应速度;

实现说明:要对response对象的输出数据进行gzip压缩,首先得拿到后面servlet(controller)进行业务处理后往response对象里写入的数据,要想实现截获输出数据,可以通过重写response对象来实现,具体方法是修改response对象内部的输出流,使该流写出数据时写出到给定的字节数组缓冲流当中,并在重写后的response对象内部提供一个获取该字节数组缓冲流的方法,这样就可以截获响应数据;拿到响应数据之后就可以对截获的响应数据通过Gzip输出流进行压缩输出即可;因为响应数据是gzip压缩格式,不是普通的文本格式,所以需要通过response对象(响应头)告知浏览器响应的数据类型,这样浏览器才可以正常解析。

代码示例

package filters;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.*;
import java.util.zip.GZIPOutputStream;

/**
 * 压缩过滤器
 *
 * 功能:对于返回给客户端的数据进行gzip压缩,提高响应速度
 * 实现说明:
 *     要对response对象的输出数据进行gzip压缩,首先得拿到后面servlet(controller)进行业务处理后往response对象里写入的数据
 *     可以通过重写response对象,修改该对象内部的输出流,使该流写出数据时写出到给定的字节数组缓冲流当中,
 *     并在重写后的response对象内部提供一个获取该字节数组缓冲流的方法,这样就可以截获响应数据
 *     然后就可以对截获的响应数据通过Gzip输出流进行压缩输出即可;
 *     因为响应数据是gzip压缩格式,不是普通的文本格式所以需要通过response对象(响应头)告知浏览器响应的数据类型
 */
@WebFilter(filterName = "GzipFilter", urlPatterns = {"/*"})
public class GzipFilter implements Filter {

    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        System.out.println("==========gzip filter");

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        MyHttpServletResponse myresponse = new MyHttpServletResponse(response);
        //pass the customized response object to controller to capture the output data
        chain.doFilter(request, myresponse);
        //get captured data
        byte[] data = myresponse.getOutputData();
        System.out.println("============截获到数据:" + data.length + " bytes");
        //get gzip data
        ByteArrayOutputStream gzipBuffer = new ByteArrayOutputStream();
        GZIPOutputStream gzipOut = new GZIPOutputStream(gzipBuffer);
        gzipOut.write(data);
        gzipOut.flush();
        gzipOut.close();
        byte[] gzipData = gzipBuffer.toByteArray();
        System.out.println("==========压缩后数据:" + gzipData.length + " bytes");
        //set response header and output
        response.setHeader("Content-Encoding", "gzip");
        response.getOutputStream().write(gzipData);
    }

    public void init(FilterConfig config) throws ServletException {
    }

    private static class MyHttpServletResponse extends HttpServletResponseWrapper {

        /**
         * 字节数组缓冲流,用来保存截获到的输出数据
         */
        private ByteArrayOutputStream buffer;
        /**
         * 重新定义servlet输出流,改变输出目的地
         * 将响应内容输出到给定的字节数组缓冲流中
         */
        private MyServletOutputStream servletOutputStream;
        /**
         * 同上
         */
        private PrintWriter writer;


        public MyHttpServletResponse(HttpServletResponse response) {
            super(response);
            //original HttpServletResponse object
            buffer = new ByteArrayOutputStream();
            servletOutputStream = new MyServletOutputStream(buffer);
            try {
                writer = new PrintWriter(new OutputStreamWriter(buffer, response.getCharacterEncoding()), true);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }

        @Override
        public ServletOutputStream getOutputStream() throws IOException {
            return servletOutputStream;
        }

        @Override
        public PrintWriter getWriter() throws IOException {
            return writer;
        }

        @Override
        public void flushBuffer() throws IOException {
            if (servletOutputStream != null) {
                servletOutputStream.flush();
            }
            if (writer != null) {
                writer.flush();
            }
        }

        /**
         * 向外部提供一个获取截获数据的方法
         * @return 从response输出流中截获的响应数据
         */
        public byte[] getOutputData() throws IOException {
            flushBuffer();
            return buffer.toByteArray();
        }

    }

    private static class MyServletOutputStream extends ServletOutputStream {

        /**
         * 字节数组缓冲流,用来保存截获到的输出数据
         */
        private ByteArrayOutputStream buffer;

        public MyServletOutputStream(ByteArrayOutputStream buffer) {
            this.buffer = buffer;
        }

        @Override
        public boolean isReady() {
            return true;
        }

        @Override
        public void setWriteListener(WriteListener listener) {
        }

        /**
         * 重写输出流相关的方法
         * 将输出数据写出到给定的ByteArrayOutputStream缓冲流中保存起来
         * @param b 输出的数据
         * @throws IOException
         */
        @Override
        public void write(int b) throws IOException {
            buffer.write(b);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值