Servlet压缩
public void doGet(HttpServletRequest request, HttpServletResponse response)
??????????? throws ServletException, IOException {
??????? //1.聲明被壓縮的數據
??????? String str = "Hello你好";
??????? //2.獲取準備壓縮的數據的字節碼
??????? byte[] src = str.getBytes("UTF-8");
??????? //3.在內存中聲明一個容器
??????? ByteArrayOutputStream destByte = new ByteArrayOutputStream();
??????? //4.聲明壓縮的工具流,并設置壓縮的目的地為destByte
??????? GZIPOutputStream zip = new GZIPOutputStream(destByte);
??????? //5.寫入數據
??????? zip.write(src);
??????? //6.關閉壓縮工具流
??????? zip.close();
??????? System.out.println("壓縮之前的字節碼大小:"+src.length);
??????? //7.獲取壓縮以后數據
??????? byte[] dest = destByte.toByteArray();
??????? System.out.println("壓縮以后的字節碼大小:"+dest.length);
??????? //8.必須要輸出壓縮以后字節數組
??????? response.setContentType("text/html;charset=UTF-8");
??????? //9.必須要使用字節流來輸出信息
??????? OutputStream out = response.getOutputStream();
??????? //10.通知瀏覽器,這是壓縮的數據,要求瀏覽器解壓
??????? response.setHeader("Content-encoding", "gzip");
??????? //11.通過瀏覽器壓縮數據的長度
??????? response.setContentLength(dest.length);
??????? //10.輸出
??????? out.write(dest);
??? }
數據必須較大才會顯示出效果
全站壓縮:
如果要對整個網站進行壓縮,那么最好的辦法就是在過濾器中寫壓縮的代碼;全站壓縮實現步驟如下
1.先簡單寫一個Servlet類,正常輸出信息
public class OneServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("Hello你好大家同學");
}
}
2.寫一個過濾器對這個Servlet類進行攔截,在攔截過程中包裝response
實現抽像類:HttpServletResponseWrapper
public class GzipFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//下面 這一段實現將數據寫到a.txt中去。
//聲明MyResponse包裝類
MyResponse resp = new MyResponse((HttpServletResponse) response);
//放行時,必須要傳遞自己包裝過的類
chain.doFilter(request, resp);
//下面這一段是讀取a.txt中的數據。
//目標類調用完成了,返回 以后讀取a.txt
File file = new File("d:/a/a.txt");
//聲明一個緩存的字符串對象
StringBuilder sb = new StringBuilder();
//讀取文件
InputStream in = new FileInputStream(file);
byte[] b = new byte[1024];
int len = 0;
while((len=in.read(b))!=-1){
sb.append(new String(b,0,len,"UTF-8"));
}
in.close();
//下面這段 壓縮數據。
//轉成字節開始壓縮
byte[] src = sb.toString().getBytes("UTF-8");
//聲明緩存容器
ByteArrayOutputStream destBytes = new ByteArrayOutputStream();
//聲明壓縮流
GZIPOutputStream gzip = new GZIPOutputStream(destBytes);
//壓縮數據
gzip.write(src);
gzip.close();
//獲取壓縮以后數據
byte[] dest = destBytes.toByteArray();
System.err.println("壓縮之前:"+src.length);
System.err.println("壓縮以后:"+dest.length);
//下面這段輸出壓縮以后數據
//輸出
//必須要使用原生 的response
HttpServletResponse res = (HttpServletResponse) response;
res.setContentType("text/html;charset=UTf-8");
OutputStream out = res.getOutputStream();
res.setHeader("Content-encoding", "gzip");//必須
res.setContentLength(dest.length);
out.write(dest);
}
public void destroy() {
}
}
//聲明包裝類
//實現對HttpSerlvetResponse的包裝
class MyResponse extends HttpServletResponseWrapper{
public MyResponse(HttpServletResponse response) {
super(response);
}
//重寫getWriter方法。
@Override
public PrintWriter getWriter() throws IOException {
System.err.println("有人想獲取輸出流");
PrintWriter out = new PrintWriter (//由于PrintWriter是GBK所以要使用轉換流。
new OutputStreamWriter(
new FileOutputStream("d:/a/a.txt"),"UTF-8"));
return out;
}
}
4.上面的代碼是存在問題的,有待完善。我們不能將每次輸出都往文件里面存,IO消耗太大,正確的做法是修改包裝類,讓輸出數據放到一個內存緩存區中
public class GzipFilter2 implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse resp= (HttpServletResponse) response;
//聲明包裝類對象
MyResponse2 myresp = new MyResponse2(resp);
//放行,調用oneServlet.doGet
chain.doFilter(request, myresp);
//第二步:從myresp2中讀取原生的數據
byte[] src = myresp.getSrc();//獲取原生的數據。
//第三步:開始壓縮
ByteArrayOutputStream destBytes = new ByteArrayOutputStream();
GZIPOutputStream zip = new GZIPOutputStream(destBytes);
zip.write(src);
zip.close();
//第三步:輸出-使用原生的response
resp.setContentType("text/html;charset=UTF-8");
//獲壓縮以后數據
byte[] dest = destBytes.toByteArray();
System.err.println("壓縮之前:"+src.length);
System.err.println("壓縮以后:"+dest.length);
//設置頭
resp.setContentLength(dest.length);
resp.setHeader("Content-Encoding","gzip");
//輸出
OutputStream out = resp.getOutputStream();
out.write(dest);
}
public void destroy() {
}
}
//第一步:聲明response的包裝類
class MyResponse2 extends HttpServletResponseWrapper{
//將這個容器/a.txt,聲明成員變量
private ByteArrayOutputStream srcByte;
public MyResponse2(HttpServletResponse response) {
super(response);
}
//修改增強getWtier方法
@Override
public PrintWriter getWriter() throws IOException {
srcByte = new ByteArrayOutputStream();
PrintWriter out =
new PrintWriter(
new OutputStreamWriter(srcByte, "UTF-8"));
return out;
}
//提供一個方法獲取原生 的數據
public byte[] getSrc(){
return srcByte.toByteArray();
}
}
5.全部的jsp都要經過壓縮
只要是通過包裝rersponse,且修改了getWriter方法,返回一個自己的printwiter對象。聲明一個放原數據的容器對象。就可以實現數據壓縮。
public class GzipFilter2 implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse resp= (HttpServletResponse) response;
//聲明包裝類對象
MyResponse2 myresp = new MyResponse2(resp);
//放行,調用oneServlet.doGet
chain.doFilter(request, myresp);
//第二步:從myresp2中讀取原生的數據
byte[] src = myresp.getSrc();
//第三步:開始壓縮
ByteArrayOutputStream destBytes = new ByteArrayOutputStream();
GZIPOutputStream zip = new GZIPOutputStream(destBytes);
zip.write(src);
zip.close();
//第三步:輸出-使用原生的response
resp.setContentType("text/html;charset=UTF-8");
//獲壓縮以后數據
byte[] dest = destBytes.toByteArray();
System.err.println("壓縮之前:"+src.length);
System.err.println("壓縮以后:"+dest.length);
//設置頭
resp.setContentLength(dest.length);
resp.setHeader("Content-Encoding","gzip");
//輸出
OutputStream out = resp.getOutputStream();
out.write(dest);
}
public void destroy() {
}
}
//第一步:聲明response的包裝類
class MyResponse2 extends HttpServletResponseWrapper{
//將這個容器/a.txt,聲明成員變量
private ByteArrayOutputStream srcByte;
private PrintWriter out;//為了可以關閉,所以將這個對象,聲明成成員變量 。
public MyResponse2(HttpServletResponse response) {
super(response);
}
//修改增強getWtier方法
@Override
public PrintWriter getWriter() throws IOException {
srcByte = new ByteArrayOutputStream();
out =
new PrintWriter(
new OutputStreamWriter(srcByte, "UTF-8"));
return out;
}
//提供一個方法獲取原生 的數據
public byte[] getSrc(){
if(out!=null){
out.close();//如果tomcat沒有關,我們自己關閉。
}
return srcByte.toByteArray();
}
}
且它的配置如下:
<filter>
<filter-name>zip2</filter-name>
<filter-class>cn.itcast.filter.GzipFilter2</filter-class>
</filter>
<filter-mapping>
<filter-name>zip2</filter-name>
<url-pattern>*.jsp</url-pattern>//對所有jsp都壓縮。
</filter-mapping>
?
6.同時實現對getoutputstream和getWtier壓縮
思想:
在myrespons2這個類中,對getoutputstream也要覆蓋。
返回一個ServletOutputSteam的匿名對象。
實現witer(int b)方法,將數據寫到bytearrayoyutpoutstream.
@Override
public ServletOutputStream getOutputStream() throws IOException {
srcByte = new ByteArrayOutputStream();
ServletOutputStream out = new ServletOutputStream() {
//所有IO最終都是一個個字節寫出信息
@Override
public void write(int b) throws IOException {
System.err.println(">>>:"+b);
srcByte.write(b);//寫到自己的緩存中去-相當于StringBuffer.append(""+b);
}
};
return out;
}
總結
- 上一篇: 部署MongoDB集群
- 下一篇: SpringMVC 使用hibernat