案例五:统一压缩响应

应用HttpServletResponseWrapper对象,压缩响应正文内容。思路:

通过filter向目标页面传递一个自定义的response对象。

在自定义的response对象中,重写getOutputStream方法和getWriter方法,使目标资源调用此方法输出页面内容时,获得的是我们自定义的ServletOutputStream对象。

在我们自定义的ServletOuputStream对象中,重写write方法,使写出的数据写出到一个buffer中。当页面完成输出后,在filter中就可得到页面写出的数据,从而我们可以调用GzipOuputStream对数据进行压缩后再写出给浏览器,以此完成响应正文件压缩功能。

1.定义HttpServletResponse的包装类

package blog.csdn.net.web.filter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

/**
 * response增强类,处理底层输出流
 * 
 * @author mChenys
 *
 */
public class MyHttpServletResponseWrapper extends HttpServletResponseWrapper {

	private HttpServletResponse response;

	// 定义用于存储调用getOutputStream或者getWriter方法时输出的数据的底层流(字节流)
	private ByteArrayOutputStream boas = new ByteArrayOutputStream();

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

	@Override
	public ServletOutputStream getOutputStream() throws IOException {
		return new MyServletOutputStream(boas);
	}

	@Override
	public PrintWriter getWriter() throws IOException {
		// 注意PrintWriter流是带缓冲功能和编码功能的
		this.mPrintWrite =new PrintWriter(new OutputStreamWriter(boas, "utf-8"));
		return mPrintWrite;
	}

	//提供一个方法, 统一返回 baos中的 数据
	public byte[] getBytes() {
		if(null !=this.mPrintWrite) {
			//强制刷新,确保 数据 可以 进到 底层流 baos中
			this.mPrintWrite.close();
		}
		//将保存在baos流对象中的数据返回给调用者
		return this.boas.toByteArray();
			
	}
}

// 处理ServletOutputStream,将其数据保存到baos流对象的类
class MyServletOutputStream extends ServletOutputStream {

	private ByteArrayOutputStream boas;

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

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

}

2.创建filter

package blog.csdn.net.web.filter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;

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

/**
 * 处理响应数据gzip压缩的filter
 * 
 * @author mChenys
 *
 */
public class GzipFilter implements Filter {

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

	}

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

		// 强转
		HttpServletRequest httpServletRequest = (HttpServletRequest) request;
		HttpServletResponse httpServletResponse = (HttpServletResponse) response;
		

		// 增强response
		MyHttpServletResponseWrapper responseWrapper = new MyHttpServletResponseWrapper(httpServletResponse);

		// 放行,传递增强后的response对象
		chain.doFilter(httpServletRequest, responseWrapper);

		// 处理响应的数据压缩
		// 创建gizp压缩流,底层是依赖字节流的
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		GZIPOutputStream gout = new GZIPOutputStream(baos);

		// 获取responseWrapper中存储的响应数据
		byte[] oldByte = responseWrapper.getBytes();
		System.out.println(" filter 压缩之前: " + oldByte.length);

		// 将响应数据写入到压缩流中
		gout.write(oldByte);
		// 注意, 这里要 关闭 一下, 这样可以 保证 数据 进到 底层流 中去
		gout.close();

		// 获取压缩后的响应数据
		byte[] newByte = baos.toByteArray();
		System.out.println(" filter 压缩 之后: " + newByte.length);

		// 通知浏览器输出的数据是 经过gzip 压缩的,
		httpServletResponse.setHeader("content-encoding", "gzip");

		// 通知 浏览器 压缩的 数据 长度
		httpServletResponse.setContentLength(newByte.length);

		// 输出压缩后的数据
		httpServletResponse.getOutputStream().write(newByte);

	}

	@Override
	public void destroy() {

	}

}

3.注册filter

<!-- 全站响应压缩处理 -->
<filter>
	<filter-name>GzipFilter</filter-name>
	<filter-class>blog.csdn.net.web.filter.GzipFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>GzipFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

4.测试

控制台输出的log

 

猜你喜欢

转载自blog.csdn.net/mChenys/article/details/81217977