1. 程式人生 > >全站壓縮---(裝飾模式、過濾器的應用)

全站壓縮---(裝飾模式、過濾器的應用)

本例子在過濾器中使用到了裝飾模式對response物件進行加強,將加強後的物件傳到servlet進行操作將資料寫到記憶體流中(呼叫的方法在response的加強中已經寫好了,使其能夠寫到記憶體流中),之後從servlet返回到過濾器再拿到記憶體流中的資料對前臺頁面進行輸出。

本例中在servlet中會呼叫到的輸出流都已經在過濾器中會呼叫到的另外的類中進行過了改造了的。

下面是程式碼:

主頁: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>
    <h2>過濾器應用示例---全站壓縮</h2>
    <a href="<c:url value='/servlet/FirstServlet'/>">請求第一個servlet--網頁壓縮輸出的基本原理</a><br/>
    <a href="<c:url value='/servlet/SecondServlet'/>">請求第二個servlet--網頁壓縮輸出的基本原理</a>
  </body>
</html>

過濾器和包裝類:

package cn.hncu.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.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 {
		
		MyResponse resp = new MyResponse((HttpServletResponse)response);
		//用增強版的resp放行到servlet中去用(讓後臺把資料 寫到  baout中 )
		
		chain.doFilter(request, resp);//放行--讓後臺去寫
		
		//從增強版的resp的baout中(存放的是源位元組資料),把資料取出來進行壓縮,
		//然後再壓縮後的資料用原生的response輸出到客戶端
		ByteArrayOutputStream baout = resp.getBaout();
		byte srcBytes[] = baout.toByteArray();//源位元組資料
		System.out.println(new String(srcBytes,"utf-8"));
		System.out.println("壓縮前大小:"+srcBytes.length);
		
		//把資料srcBytes 壓縮到 baout2
		ByteArrayOutputStream baout2 = new ByteArrayOutputStream();
		GZIPOutputStream gzip = new GZIPOutputStream(baout2);
		gzip.write(srcBytes);//把資料壓縮到baout2中
		gzip.close();
		
		//把baout2中的資料(壓縮後) 取出來,用原生response以gzip格式輸出到客戶端
		byte destBytes[] = baout2.toByteArray();
		System.out.println("壓縮後大小:"+destBytes.length);
		//輸出之前告訴客戶端:我們的資料是gzip格式,然後輸出
		HttpServletResponse httpResp =(HttpServletResponse) response;
		httpResp.setHeader("Content-Encoding", "gzip");
		httpResp.setContentLength(destBytes.length);
		OutputStream out = httpResp.getOutputStream();
		out.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);
	}
	
	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 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中了
	}
}

兩個不同輸出型別的servlet

輸出位元組FirstServlet

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 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="網頁壓縮資料hncuhdncu網頁壓縮資料hncuh資料hncuhdncu網頁壓縮資料hncuh資料hncuhdncu網頁壓縮資料hncuhdncu網頁壓縮資料hncuhdncu";
		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採用的方式
	}
}

輸出字元SecondServlet

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 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="網頁壓縮資料hncuhdncu網頁壓縮資料hncuh資料hncuhdncu網頁壓縮資料hncuh資料hncuhdncu網頁壓縮資料hncuhdncu網頁壓縮資料hncuhdncu";
		System.out.println("原大小: "+str.getBytes("utf-8").length);
		
		PrintWriter out=response.getWriter();
		out.write(str);
		out.close();
	}
}

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">
  
  <filter>
  	<filter-name>gzip</filter-name>
  	<filter-class>cn.hncu.filter.GZipFilter</filter-class>
  </filter>
  
  <filter-mapping>
  	<filter-name>gzip</filter-name>
  	<url-pattern>/servlet/*</url-pattern>
  </filter-mapping>

  <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-mapping>
    <servlet-name>FirstServlet</servlet-name>
    <url-pattern>/servlet/FirstServlet</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>SecondServlet</servlet-name>
    <url-pattern>/servlet/SecondServlet</url-pattern>
  </servlet-mapping>

</web-app>