Filter过滤器(gzip) 全站 压缩

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 方法
	
}

原文链接: Filter过滤器(gzip) 全站 压缩 版权所有,转载时请注明出处,违者必究。
注明出处格式:流沙团 ( https://gyarmy.com/post-88.html )

发表评论

0则评论给“Filter过滤器(gzip) 全站 压缩”