高手不得不會的東西
背景:項目使用的SOA架構,使用Oracle10G SOA SUITE,在該套件中增加了一個過濾器用於解析設定的存取原則。在其中遇到了一個問題,Oracle10g無法將IP與執行個體編號進行綁定,於是乎從過濾器入手,嘗試了HttpServletRequestWrapper、HttpServletResponseWrapper攔截設定參數的方法。得到的結果request可以對請求參數進行修改,但是這樣可能會導致Oracle10g SOA Suite的正常運行,想從response中獲得返回的內容,但是得到的結果是null,到目前為止該問題仍舊沒有得到解決,有好辦法的歡迎聯絡本人,謝謝。
| 1)建立一個響應封裝器。擴充javax.servlet.http.HttpServletResponseWrapper。 2)提供一個緩衝輸出的PrintWriter。重載getWriter方法,返回一個儲存發送給它的所有東西的PrintWriter,並把結果存進一個可以稍後訪問的欄位中。 3)傳遞該封裝器給doFilter。此調用是合法的,因為HttpServletResponseWrapper實現HttpServletResponse。 4)提取和修改輸出。在調用FilterChain的doFilter方法後,原資源的輸出只要利用步驟2中提供的機制就可以得到。只要對你的應用適合,就可以修改或替換它。 5)發送修改過的輸出到客戶機。因為原資源不再發送輸出到客戶機(這些輸出已經存放到你的響應封裝器中了),所以必鬚髮送這些輸出。這樣,你的過濾器需要從原響應對象中獲得PrintWriter或OutputStream,並傳遞修改過的輸出到該流中。 (2).GZipFilter類 (3).GZipUtil類 (4).在web.xml中配置 GZipFilter |
下附HttpServletRequestWrapper、HttpServletResponseWrapper用法
class FilteredRequest extends HttpServletRequestWrapper { public FilteredRequest(ServletRequest request) { super((HttpServletRequest) request); } public String getParameter(String paramName) { String value = super.getParameter(paramName); if ("myParameter".equals(paramName)) { // 變更要求參數的值 value += "|127.0.0.1"; } return value; } public String[] getParameterValues(String paramName) { String values[] = super.getParameterValues(paramName); return values; } }
import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.PrintWriter;import java.io.UnsupportedEncodingException;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpServletResponseWrapper;public class WrapperResponse extends HttpServletResponseWrapper{ private MyPrintWriter tmpWriter; private ByteArrayOutputStream output; public WrapperResponse(ServletResponse httpServletResponse) { super((HttpServletResponse)httpServletResponse); output = new ByteArrayOutputStream(); tmpWriter = new MyPrintWriter(output); } public void finalize() throws Throwable { super.finalize(); output.close(); tmpWriter.close(); } public String getContent() { try { tmpWriter.flush(); //重新整理該流的緩衝,詳看java.io.Writer.flush() String s = tmpWriter.getByteArrayOutputStream().toString("UTF-8"); //此處可根據需要進行對輸出資料流以及Writer的重設操作 //比如tmpWriter.getByteArrayOutputStream().reset() return s; } catch (UnsupportedEncodingException e) { return "UnsupportedEncoding"; } } //覆蓋getWriter()方法,使用我們自己定義的Writer public PrintWriter getWriter() throws IOException { return tmpWriter; } public void close() throws IOException { tmpWriter.close(); } //自訂PrintWriter,為的是把response流寫到自己指定的輸入資料流當中 //而非預設的ServletOutputStream private static class MyPrintWriter extends PrintWriter { ByteArrayOutputStream myOutput; //此即為存放response輸入資料流的對象 public MyPrintWriter(ByteArrayOutputStream output) { super(output); myOutput = output; } public ByteArrayOutputStream getByteArrayOutputStream() { return myOutput; } }}
調用處
FilteredRequest filterRequest = new FilteredRequest(request);WrapperResponse filterResponse = new WrapperResponse(response);filterChain.doFilter(filterRequest, filterResponse);String content = filterResponse.getContent();
或者自己實現HttpServletResponse和HttpServletRequest介面,但這是麻煩的。
如果要管理session,或session實現共用就用HttpSessionWrapper
學習oscache頁面緩衝得到的啟示 :http://blog.sina.com.cn/s/blog_866b16a60100z2bi.html
首先說一個無關的,但高手必須瞭解的。 servlet的Response的輸出資料流在URL中儲存Session ID的方法是哪一個。 A. the encodeURL method of the HttpServletRequest interface B. the encodeURL method of the HttpServletResponse interface C. the rewriteURL method of the HttpServletRequest interface D. the rewriteURL method of the HttpServletResponse interface
答案選B.
學習完黎老師講的oscache頁面緩衝後,它的實現原理大致如下(原理和oscache一樣,但oscache做的更好,我這裡只是用虛擬碼簡單描述): Cachefilter
implements filter{ dofilter(request, response, chain){ String urlpath = req,...; if(Oscache.contains(urlpath)){ String content = oscache.getKey(urlpath); response.write(content); }else{ CacheHettpServletResponseWrapper wrapper = new CacheHettpServletResponseWrapper (respone); chain.doFilter(reques, wrapper); String content = wrapper.getContent();//擷取服務端往用戶端輸出的html代碼 Oscache.put(urlpath, content); response.write(content); } } }
public CacheHettpServletResponseWrapper extends HettpServletResponseWrapper{ private String content; public CacheHettpServletResponseWrapper(HttpServletResponse response){ ....... } //重寫HettpServletResponseWrapper的一個方法,這裡可能不是write方法,忘記叫什麼了,自己去看。後來看了下是 /覆蓋getWriter()方法,使用我們自己定義的Writer
public PrintWriter getWriter()
throws IOException
HettpServletResponseWrapper吧 public void getWriter(String Content){ this.Content = content; } public String getContent(){ return this.content; } }
:利用繼承 HettpServletResponseWrapper可以控制往用戶端的輸出,或在往用戶端輸出前取得要輸出的內容。 同樣希望大家會 HttpServletRequestWrapper。 或者自己實現 HttpServletResponse和 HttpServletRequest介面,但這是麻煩的。
| 1)建立一個響應封裝器。擴充javax.servlet.http.HttpServletResponseWrapper。 2)提供一個緩衝輸出的PrintWriter。重載getWriter方法,返回一個儲存發送給它的所有東西的PrintWriter,並把結果存進一個可以稍後訪問的欄位中。 3)傳遞該封裝器給doFilter。此調用是合法的,因為HttpServletResponseWrapper實現HttpServletResponse。 4)提取和修改輸出。在調用FilterChain的doFilter方法後,原資源的輸出只要利用步驟2中提供的機制就可以得到。只要對你的應用適合,就可以修改或替換它。 5)發送修改過的輸出到客戶機。因為原資源不再發送輸出到客戶機(這些輸出已經存放到你的響應封裝器中了),所以必鬚髮送這些輸出。這樣,你的過濾器需要從原響應對象中獲得PrintWriter或OutputStream,並傳遞修改過的輸出到該流中。 (2).GZipFilter類 (3).GZipUtil類 (4).在web.xml中配置 GZipFilter |
-------------------------------------------------- 頁面緩衝 ---》html--->client 二級緩衝 --》action-->service層--> Jsp-->html-->client
:從上看出為什麼頁面緩衝要比二級緩衝要快。因為二級緩衝處理流程更多,並且還要解析jsp及標籤等轉化成html,這是耗時的。