過濾器(Filter)應用:全站壓縮----Gzip網頁壓縮輸出
阿新 • • 發佈:2019-01-23
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>
注意:字元流在讀寫時,一定要關流!
全站壓縮後的網頁是不影響正常訪問的,區別就是,流量減少了,速度提高了。在訪問的過程中,是難以察覺的。