流沙团
Filter过滤器(gzip) 全站 压缩
2016-8-1 流沙团
package com.itheima.filter;

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 FilterConfig config;

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

this.config = filterConfig;
}

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

HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;

String encoding = config.getInitParameter("encoding");
request.setCharacterEncoding(encoding);
response.setContentType("text/html;charset="+encoding);
//

// response.setCharacterEncoding("")


// HttpServletRequestWrapper ---对request 进行 包装的包装类 ---- 解决全站的 请求数据的乱码

//HttpServletResponseWrapper ----对response 进行 包装的 包装类 ---- 解决全站的 响应的数据的 压缩

MyHttpServletResponseWrapper myresponse = new MyHttpServletResponseWrapper(response);


//放行
chain.doFilter(request, myresponse); // --- 目标 资源会得到 执行


System.out.println("之后 ...");

// 将 写到 myresponse 里的数据 进行 压缩 , 然后 输出到 浏览器 去

//这里 报错的 原因是 因为
// 没有 原始的数据(压缩前的数据), 那么 如果 能够 将原始的 压缩前的数据 拿到
// 所有的问题就 都解决了...
// byte[] b = data.getBytes();
byte[] b = myresponse.getOldData();


System.out.println("压缩前: " + b.length);

//底层流
ByteArrayOutputStream baos = new ByteArrayOutputStream();

//采用gzip压缩

//这里 压缩的时候, 需要的是一个 输出流, 这里的输出流是一个底层流
GZIPOutputStream gout= new GZIPOutputStream(baos);
gout.write(b);

gout.close(); //确保 数据可以写到 底层流 baos中去

//这里 要注意: 由于 数据是写到 底层流 baos中去的, gout 默认的是有 缓冲区的 .

b = baos.toByteArray();

System.out.println("压缩后 : " +b.length);

//告诉浏览器 需要 解压缩 数据-- 通过 http的响应头 实现
response.setHeader("content-encoding", "gzip");
response.setContentLength(b.length); //数据的长度

response.getOutputStream().write(b);


}

@Override
public void destroy() {

}

}

class MyHttpServletResponseWrapper extends HttpServletResponseWrapper{

private HttpServletResponse response;

public MyHttpServletResponseWrapper(HttpServletResponse response) {
super(response);
this.response= response;
}

ByteArrayOutputStream bout = new ByteArrayOutputStream();


//通过 这个方法 可以 拿到 原始的 数据
public byte[] getOldData(){


if(pw!=null){
pw.close();
}

return bout.toByteArray();
}

PrintWriter pw = null;
@Override
public PrintWriter getWriter() throws IOException {

//字符输出流, 有缓冲区 ,
if(pw==null){

//字符输出流 ----- bout (字节流)
pw = new PrintWriter(new OutputStreamWriter(bout, response.getCharacterEncoding()));
}
return pw;
}

@Override
public ServletOutputStream getOutputStream() throws IOException {

//在 调用这个 方法的时候, 数据 写到 一个 俺们自己 定义的输出流去, 那么这样 数据就进入了 自己 定义的输出流中去 了 .
return new MyServletOutputStream(bout);
}
}

class MyServletOutputStream extends ServletOutputStream{

private OutputStream out;


public MyServletOutputStream(OutputStream out){
this.out = out;
}


//最终 是 调用到 这个 方法里 了 .

//所有的数据 都进入 到了 out 中去 了,而这里 out 又 是 MyHttpServletResponseWrapper 里的 bout 了, 所以 所有的数据 都 在 bout 中了
@Override
public void write(int b) throws IOException {
out.write(b);
}

// 这里 没有 一个 接受 字节 数组的write 方法

}
发表评论:
昵称

邮件地址 (选填)

个人主页 (选填)

内容