使用filter实现网站的gzip压缩

使用filter实现网站的gzip压缩

gzip可以提高网站的访问速度,所以还是有必要开启的,这里说说如何用filter实现


直接上代码

package com.educate.web.filter;

import com.educate.web.interceptor.LoginInterceptor;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.zip.GZIPOutputStream;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class GzipFilter implements Filter {


    private static final Logger LOGGER = LoggerFactory.getLogger(GzipFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res,
                         FilterChain chain) throws IOException, ServletException {


        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        if (isGZipEncoding(request)) {


            //需要过滤的扩展名:.htm,.html,.jsp,.js,.ajax,.css,.ftl,.txt, 一般这些已经足够了,不建议压缩图片(具体百度)
            String gzipPattern = ",.htm,.html,.jsp,.js,.ajax,.css,.ftl,.txt,";
            String uri = request.getRequestURI();
            //得到资源的后缀
            String ext = FilenameUtils.getExtension(uri);

            if (StringUtils.indexOf(gzipPattern, ",." + ext + ",") != -1) {

                MyResponse resp = new MyResponse(response);
                chain.doFilter(request, resp);// 放行--让后台去写

                // 从增强版的resp的baout中(存放的是源字节数据),把数据取出来进行压缩,
                // 然后再压缩后的数据用原生的response输出到客户端
                ByteArrayOutputStream baout = resp.getBaout();
                byte bs[] = baout.toByteArray();// 源字节数据
                //太小的不压缩
                if (bs.length > 512) {

                    LOGGER.debug("过滤的资源路径:" + uri);
                    LOGGER.debug("压缩前大小:" + bs.length);

                    ByteArrayOutputStream baout2 = new ByteArrayOutputStream();
                    GZIPOutputStream gout = new GZIPOutputStream(baout2);
                    gout.write(bs);// 把数据压缩到baout中
                    gout.close();

                    bs = baout2.toByteArray();
                    LOGGER.debug("压缩后大小:" + bs.length);

                    // 输出之前告诉客户端:我们的数据是gzip格式,然后输出
                    response.setHeader("Content-Encoding", "gzip");
                    response.setContentLength(bs.length);
                }

                ServletOutputStream output = response.getOutputStream();
                output.write(bs);
                output.flush();
            } else {
                chain.doFilter(request, response);
            }
            return;
        } else {
            chain.doFilter(request, response);
        }


    }

    /**
     * 判断浏览器是否支持GZIP
     *
     * @param request
     * @return
     */
    private boolean isGZipEncoding(HttpServletRequest request) {
        boolean flag = false;
        String encoding = request.getHeader("Accept-Encoding");
        if (encoding.indexOf("gzip") != -1) {
            flag = true;
        }
        return flag;
    }

    @Override
    public void destroy() {
    }

}

class MyResponse extends HttpServletResponseWrapper {
    private ByteArrayOutputStream baout = new ByteArrayOutputStream();

    public MyResponse(HttpServletResponse response) {
        super(response);
    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return new MyOutputStream(baout);
    }

    public ByteArrayOutputStream getBaout() {
        if (pw != null) {
            pw.flush();
            //这里很重要,如果不flush或close,不把字符流刷出去,baout中是不会有数据的.
        }
        return baout;
    }

    private PrintWriter pw;

    @Override
    public PrintWriter getWriter() throws IOException {
        pw = new PrintWriter(new OutputStreamWriter(baout, "utf-8"), true);
        return pw;
    }

}

class MyOutputStream extends ServletOutputStream {
    private ByteArrayOutputStream baout = null;

    public MyOutputStream(ByteArrayOutputStream baout) {
        this.baout = baout;
    }

    @Override
    public void write(int b) throws IOException {
        baout.write(b);
    }
}

最后在web.xml中配置一下

<!-- gzip压缩 减少网络流量,加快响应速度 -->
    <filter>
        <filter-name>gzip</filter-name>
        <filter-class>com.educate.web.filter.GzipFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>gzip</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值