1. 程式人生 > >過濾器(Filter)應用:全站壓縮----Gzip網頁壓縮輸出

過濾器(Filter)應用:全站壓縮----Gzip網頁壓縮輸出

Filter應用-7

實現壓縮的輸出流。 現在的網路,流量就是錢。所以,如果能在很少的流量的情況下,檢視相同的資料內容,那何樂而不為呢? 實現方案: 使用者在呼叫response.getOutputStream()時讓獲取自己的輸出流對像, 我們將資訊寫到事先準備好的快取當中。 當用戶書寫完畢,我們再呼叫自己提供的方法,獲取快取中的資料流 然後接著對資料進行壓縮,在過慮器中,將資訊返回給使用者,從而實現資料的壓縮。 那麼如何使用者呼叫response.getWriter進行輸出時,我們怎麼辦呢? 能不能也對jsp所有輸出進行壓縮呢? 可以處理中文亂碼問題嗎?

配置只對部分和

.jsp壓縮,其他的不壓縮,

還應配置對.js.css壓縮

但決不能配置對所有請求都壓縮,因為如果使用者請求的是下載,那不但不能壓縮,反而會讓

伺服器因記憶體益處而崩潰。

canGzipWeb

在學習的過程中,分成三段,先是位元組流壓縮,然後是字元流壓縮,最後是二者都可以壓縮。

主頁index.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core"	prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>過濾器應用之全站壓縮</title>
  </head>
  
  <body>
   <h1>過濾器應用之全站壓縮</h1>
   <a href="<c:url value='/FirstServlet' />">請求第一個servlet----網頁壓縮的基本原理</a><br/>
   <a href="<c:url value='/OutputStream/SecondServlet' />">請求第二個servlet----用過濾器壓縮輸出位元組流資料</a><br/>
   <a href="<c:url value='/Write/ThirdServlet' />">請求第三個個servlet----用過濾器壓縮輸出字元流資料</a><br/>
  </body>
</html>

FirstServlet.java  這裡主要是知道壓縮的基本原理,是在servlet直接壓縮,沒有經過過濾器壓縮的

package cn.hncu.servlets;

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

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/*
 * 資料壓縮的基本原理:
 * 1.源資料
 * 2.ByteArrayOutputStream位元組資料流
 * 3.GZIPOutputStream位元組壓縮流
 * new GZIPOutputStream時把ByteArrayOutputStream放進去,然後GZIPOutputStream寫資料,即寫到位元組陣列中,然後位元組陣列再輸出來
 */
public class FirstServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doPost(request, response);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		response.setContentType("text/html;charset=utf-8");
		
		String str="hncu湖南城院hncu湖南城院hncu湖南城院hncu湖南城院hncu湖南城院hncu湖南城院hncu湖南城院hncu湖南城院";
		System.out.println("before1:"+str.getBytes("utf-8").length);
		System.out.println("before2:"+str.getBytes().length);
		
		//壓縮輸出:把源資料通過GZIPOutputStream壓縮到ByteArrayOutputStream中
		ByteArrayOutputStream baout=new ByteArrayOutputStream();
		GZIPOutputStream gzip=new GZIPOutputStream(baout);
		gzip.write(str.getBytes("utf-8"));
		gzip.close();
		
		//從baout中記憶體流中把壓縮後的資料取出來,然後輸出到客戶端
		byte[] dest=baout.toByteArray();
		System.out.println("after:"+dest.length);
		
		//在輸出之前要告訴客戶端資料是gzip格式
		response.setHeader("Content-Encoding", "gzip");
		response.setContentLength(dest.length);
		response.getOutputStream().write(dest);
	}
}


位元組壓縮:

GzipFilter1.java

package cn.hncu.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.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class GzipFilter1 implements Filter{

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

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		//把增強的resp放進去,放行到後臺(在後臺把資料寫到baout中)
		MyResponse resp=new MyResponse((HttpServletResponse) response);
		
		chain.doFilter(request, resp);//放行,到後臺去寫資料
		
		//回來的時候攔住,從增強版的resp中把baout(源資料)壓縮並用原response輸出到客戶端
		ByteArrayOutputStream baout=resp.getBaout();
		byte srcBytes[]=baout.toByteArray();//源位元組資料
		System.out.println("過濾器中:"+srcBytes.length);
		
		ByteArrayOutputStream baout2=new ByteArrayOutputStream();
		GZIPOutputStream gzip=new GZIPOutputStream(baout2);
		gzip.write(srcBytes);
		gzip.close();//注意:此處一定要關流
		byte[] destBytes=baout2.toByteArray();
		System.out.println("壓縮之後的資料長度:"+destBytes.length);
		
		//輸出之前告訴客戶端我們是gzip格式
		HttpServletResponse httpResp=(HttpServletResponse) response;
		httpResp.setHeader("Content-Encoding", "gzip");
		httpResp.setContentLength(destBytes.length);
		response.getOutputStream().write(destBytes);
	}

	@Override
	public void destroy() {
	}

}
class MyResponse extends HttpServletResponseWrapper{
	private ByteArrayOutputStream baout;
	public MyResponse(HttpServletResponse response) {
		super(response);
		baout=new ByteArrayOutputStream();
	}

	@Override
	public ServletOutputStream getOutputStream() throws IOException {
		return new MyOutputStream(baout);
	}
	public ByteArrayOutputStream getBaout(){
		return baout;
	}
	
}
class MyOutputStream extends ServletOutputStream{
	private ByteArrayOutputStream baout;
	public MyOutputStream(ByteArrayOutputStream baout) {
		this.baout=baout;
	}

	@Override
	public void write(int b) throws IOException {
		baout.write(b);//把資料寫到baout中了
	}
	
}

SecondServlet.java

package cn.hncu.servlets;

import java.io.IOException;
import java.io.OutputStream;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class SecondServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doPost(request, response);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		
		String str="";
		for(int i=0;i<=1024;i++){
			str+=i;
		}
		System.out.println("原資料大小:"+str.getBytes("utf-8").length);
		OutputStream out=response.getOutputStream();
		out.write(str.getBytes("utf-8"));//注:雖然MyEclipse環境設定的是utf-8編碼,但本句str.getBytes()仍以gbk方式編碼---應該是Tomcat中的JVM採用的方式
	}

}

字元壓縮:

GzipFilter2.java

package cn.hncu.filter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
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.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class GzipFilter2 implements Filter{

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

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		//把增強的resp放進去,放行到後臺(在後臺把資料寫到baout中)
		MyResponse2 resp=new MyResponse2((HttpServletResponse) response);
		
		chain.doFilter(request, resp);//放行,到後臺去寫資料
		
		//回來的時候攔住,從增強版的resp中把baout(源資料)壓縮並用原response輸出到客戶端
		ByteArrayOutputStream baout=resp.getBaout();
		byte srcBytes[]=baout.toByteArray();//源位元組資料
		System.out.println("過濾器中:"+srcBytes.length);
		
		ByteArrayOutputStream baout2=new ByteArrayOutputStream();
		GZIPOutputStream gzip=new GZIPOutputStream(baout2);
		gzip.write(srcBytes);
		gzip.close();//注意:此處一定要關流
		byte[] destBytes=baout2.toByteArray();
		System.out.println("壓縮之後的資料長度:"+destBytes.length);
		
		//輸出之前告訴客戶端我們是gzip格式
		HttpServletResponse httpResp=(HttpServletResponse) response;
		httpResp.setHeader("Content-Encoding", "gzip");
		httpResp.setContentLength(destBytes.length);
		response.getOutputStream().write(destBytes);
	}

	@Override
	public void destroy() {
	}

}
class MyResponse2 extends HttpServletResponseWrapper{
	private ByteArrayOutputStream baout;
	public MyResponse2(HttpServletResponse response) {
		super(response);
		baout=new ByteArrayOutputStream();
	}
	@Override
	public PrintWriter getWriter() throws IOException {
		return new PrintWriter(new OutputStreamWriter(baout, "utf-8"));
	}
	public ByteArrayOutputStream getBaout(){
		return baout;
	}
}


ThirdServlet.java

package cn.hncu.servlets;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ThirdServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doPost(request, response);
	}
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		
		StringBuilder sb=new StringBuilder();
		String str="";
		for(int i=0;i<1024;i++){
			sb.append(i+"你好");
		}
		str=sb.toString();
		System.out.println("壓縮前資料長度:"+str.getBytes("utf-8").length);
		System.out.println("壓縮前資料長度:"+str.getBytes().length);
		PrintWriter pw=response.getWriter();
		pw.println(str);
		pw.close();//關流
	}

}

完整版本的二者都可以壓縮:

GzipFilter.java

package cn.hncu.filter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
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.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

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 {
		MyHttpServletResponse resp=new MyHttpServletResponse((HttpServletResponse) response);
		
		chain.doFilter(request, resp);
		
		ByteArrayOutputStream baout=resp.getBaout();
		byte[] srcBytes=baout.toByteArray();
		System.out.println("srcBytes的長度:"+srcBytes.length);
		ByteArrayOutputStream baout2=new ByteArrayOutputStream();
		GZIPOutputStream gzip=new GZIPOutputStream(baout2);
		gzip.write(srcBytes);
		gzip.close();
		
		byte[] destBytes=baout2.toByteArray();
		HttpServletResponse httpResp=(HttpServletResponse) response;
		httpResp.setHeader("Content-Encoding", "gzip");
		httpResp.setContentLength(destBytes.length);
		httpResp.getOutputStream().write(destBytes);
	}

	@Override
	public void destroy() {
	}

}
class MyHttpServletResponse extends HttpServletResponseWrapper{
	private ByteArrayOutputStream baout;
	public MyHttpServletResponse(HttpServletResponse response) {
		super(response);
		baout=new ByteArrayOutputStream();
	}
	@Override
	public ServletOutputStream getOutputStream() throws IOException {
		return new MyOutputStream3(baout);
	}
	PrintWriter pw=null;
	@Override
	public PrintWriter getWriter() throws IOException {
		pw=new PrintWriter(new OutputStreamWriter(baout, "utf-8"),true);
		return pw;
	}
	public ByteArrayOutputStream getBaout(){
		if(pw!=null){
			pw.close();
		}
		return baout;
	}
}
class MyOutputStream3 extends ServletOutputStream{
	private ByteArrayOutputStream baout;
	public MyOutputStream3(ByteArrayOutputStream baout) {
		this.baout=baout;
	}

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


web.xml的配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 
	xmlns="http://java.sun.com/xml/ns/javaee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  <display-name></display-name>
  <filter>
  	<filter-name>GzipFilter1</filter-name>
  	<filter-class>cn.hncu.filter.GzipFilter1</filter-class>
  </filter>
  <filter>
  	<filter-name>GzipFilter2</filter-name>
  	<filter-class>cn.hncu.filter.GzipFilter2</filter-class>
  </filter>
  <filter>
  	<filter-name>GzipFilter</filter-name>
  	<filter-class>cn.hncu.filter.GzipFilter</filter-class>
  </filter>
  <servlet>
    <servlet-name>FirstServlet</servlet-name>
    <servlet-class>cn.hncu.servlets.FirstServlet</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>SecondServlet</servlet-name>
    <servlet-class>cn.hncu.servlets.SecondServlet</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>ThirdServlet</servlet-name>
    <servlet-class>cn.hncu.servlets.ThirdServlet</servlet-class>
  </servlet>


	<!-- 
	<filter-mapping>
		<filter-name>GzipFilter1</filter-name>
		<url-pattern>/OutputStream/*</url-pattern>
	</filter-mapping>
	<filter-mapping>
		<filter-name>GzipFilter2</filter-name>
		<url-pattern>/Write/*</url-pattern>
	</filter-mapping>
	 -->
	
	<filter-mapping>
		<filter-name>GzipFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
  <servlet-mapping>
    <servlet-name>FirstServlet</servlet-name>
    <url-pattern>/FirstServlet</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>SecondServlet</servlet-name>
    <url-pattern>/OutputStream/SecondServlet</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>ThirdServlet</servlet-name>
    <url-pattern>/Write/ThirdServlet</url-pattern>
  </servlet-mapping>	
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>


注意:字元流在讀寫時,一定要關流!

全站壓縮後的網頁是不影響正常訪問的,區別就是,流量減少了,速度提高了。在訪問的過程中,是難以察覺的。