全站压缩过滤器
2019獨角獸企業重金招聘Python工程師標準>>>
?package?com.techsboy.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.annotation.WebFilter; import?javax.servlet.http.HttpServletRequest; import?javax.servlet.http.HttpServletResponse; import?javax.servlet.http.HttpServletResponseWrapper;/** *?tip:?PrintWriter,ServletOutputStream,JspWriter的輸出過程*?response對象getOutputSteam()和getWriter()方法分別獲得ServletOutputStream?out*?和PrintWriter?writer輸出對象,out.write(..),out.print(..)和out.println(..)方法*?最終都要使用out的write(int?b)方法來輸出數據。writer.write(..),writer.print(..),*?writer.println(..)方法可以自定義指定的流(通過PrintWriter的構造方法注入指定的流)*?來將字符流轉換成字節流輸出。JspWriter的輸出最終是輸出到PrintWriter的緩存的前面, *?(因此總是優先輸出PrintWriter的數據,在輸出JspWriter的數據,除非調用flush()),*?因此在調用JspWriter輸出前會使用response獲得PrintWriter對象,將數據輸出到該對象*?指定的緩存中,然后再用PrintWriter對象輸出客戶端。*?由上可見,解決全站壓縮問題要把住前兩個輸出對象的最后輸出關口,在關口處獲得數據*?壓縮處理,然后在把壓縮后的數據輸出。(注意?struts2會獲取兩次PrintWriter對象)*?全站壓縮過濾器類,負責將所有輸出都經過壓縮后反饋給客戶端*/ @WebFilter("/*") public?class?GZIPCompressFilter?implements?Filter?{/***?@see?Filter#doFilter(ServletRequest,?ServletResponse,?FilterChain)*/public?void?doFilter(ServletRequest?req,?ServletResponse?resp,?FilterChain?chain)?throws?IOException,?ServletException?{HttpServletRequest?request?=?(HttpServletRequest)req;HttpServletResponse?response?=?(HttpServletResponse)resp;//在壓縮前對response方法進行改寫,采用繼承包裝類的方法實現MyHttpServletResponse?myResponse?=?new?MyHttpServletResponse(response);chain.doFilter(request,?myResponse);//提取源數據進行壓縮,使用源輸出流輸出//獲取源數據byte[]?b?=?myResponse.getSourceData();if(b.length!=0){//帶緩存的字節數組輸出流,存放壓縮后的數據ByteArrayOutputStream?byteOut?=?new?ByteArrayOutputStream();//對源數據進行壓縮GZIPOutputStream?gzip?=?new?GZIPOutputStream(byteOut);gzip.write(b);gzip.close();//將壓縮的數據輸出給客戶端,同時通知客戶端解壓縮格式和內容長度byteOut.flush();b?=?byteOut.toByteArray();response.setHeader("Content-Encoding",?"gzip");response.setContentLength(b.length);response.getOutputStream().write(b);}}/***?@see?Filter#init(FilterConfig)*/public?void?init(FilterConfig?fConfig)?throws?ServletException?{}@Overridepublic?void?destroy()?{} }/***?自定義類繼承HttpServletResponse包裝類,改寫父類response獲得輸出流的兩個方法,從而*?實現所有輸出的數據被指定到一個帶緩存的字節數組輸出流中,以便可以方便的獲得輸出的*?源數據,來進行壓縮操作。*/ class?MyHttpServletResponse?extends?HttpServletResponseWrapper?{private?ByteArrayOutputStream?byteOut?=?new?ByteArrayOutputStream();private?PrintWriter?writer?=?null;public?MyHttpServletResponse(HttpServletResponse?response)?{super(response);}/***?改寫父類的方法,創建一個類繼承ServletOutputStream(并注入一個帶緩存的字節數組輸出流對象),*?該類改寫父類的write(int?b)方法,使得使用該類對象的方法輸出的數據都將輸出到字節數組輸出流的*?緩存中?*/@Overridepublic?ServletOutputStream?getOutputStream()?throws?IOException?{MyServletOutputStream?myOut?=?new?MyServletOutputStream(byteOut);return?myOut;}/***?改寫父類的方法,返回一個帶自己設定輸出流的PrintWriter對象*/@Overridepublic?PrintWriter?getWriter()?throws?IOException?{//?這是錯的,該輸出流將字符流轉換成字節流使用的是平臺默認字符集編碼ISO-8859-1 //??PrintWriter?writer?=?new?PrintWriter(byteOut);//下面才是正解,不過要注意判斷writer是否已經被創建過,創建過就不要再創建了, //否則第一個writer的內容就得不到輸出。 //struts2就是這種情形,他會調用該方法兩次生成兩次writerif(writer==null)writer?=?new?PrintWriter(new?OutputStreamWriter(byteOut,super.getCharacterEncoding()),true);return?writer;}/***?獲取源數據的字節數組*?@return?源數據的一個字節數組*/public?byte[]?getSourceData(){try?{if(writer!=null){writer.close();}byteOut.flush();}?catch?(IOException?e)?{throw?new?RuntimeException(e);}return?byteOut.toByteArray();} }/***?實現ServletOutputStream的輸出流(注入一個帶緩存的字節數組輸出流),*?改寫了父類的write(int?b)方法,實現該輸出流輸出數據統一指定到字節數組輸出流緩存中。*/ class?MyServletOutputStream?extends?ServletOutputStream{private?ByteArrayOutputStream?byteOut;public?MyServletOutputStream(ByteArrayOutputStream?byteOut){this.byteOut?=?byteOut;}@Overridepublic?void?write(int?b)?throws?IOException?{byteOut.write(b);} }轉載于:https://my.oschina.net/techsboy/blog/221988
總結
- 上一篇: 【VMCloud云平台】SCVMM配置(
- 下一篇: AIX-df命令