思路:使用filter攔截servlet或者jsp頁面內容,比如內容替換,再向使用者展現修改後的頁面
使用普通的filter攔截頁面內容,會出現這種情況
從入中可以看出,輸出內容並沒有通過過濾器就輸出了。
從入中可以看出,輸出內容並沒有通過過濾器就輸出了。
既然使用普通filter不能達到目的,那麼就換一種方法,在Servlet或者jsp接收到response之前,將response使用一個“假的response”替換,讓servlet或者jsp的內容輸出到這個“假的response”中,然後再對輸出內容進行處理,最後再將整個通過真的response輸出給用戶端
圖示如下:
實現上圖的步驟:
1.建立一個filter--用來使用"假的response"替換掉實際的response
2.建立一個“假的response"--繼承HttpServletResponseWrapper類即可
3.在filter進行替換內容和實際輸出
主要類的代碼如下:
filter:
public class ContentChangeFilter implements Filter{public void destroy() {}public void doFilter(ServletRequest request, ServletResponse response, FilterChain fc) throws IOException, ServletException {CoverResponse cr = new CoverResponse((HttpServletResponse)response);fc.doFilter(request, cr);//處理替換String content = cr.getContent();content = content.replace("test", "actual");response.getWriter().print(content);}public void init(FilterConfig arg0) throws ServletException {}}
假的resonse:
public class CoverResponse extends HttpServletResponseWrapper{private MyPrintWriter tmpWriter;private ByteArrayOutputStream output;public CoverResponse(HttpServletResponse response) {super(response);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; } } }
功能是將輸出頁面中的test替換為actual.
經過測試發現,如果向“假的response”添加cookie,是可以將cookie正常放到用戶端的。這可能也是為什麼建立“假的response”需要原response的一個引用的原因之一吧。
modify 2012-09-20
經過實際使用,發現使用字元流作為PrintWriter的目的地會造成亂碼的情況,鑒於反覆編碼比較困難,所以使用更簡單的StringWriter作為輸出目的地。
package com.aspire.pams.tag.sichuan.tools;import java.io.IOException;import java.io.PrintWriter;import java.io.StringWriter;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpServletResponseWrapper;public class CoverResponse extends HttpServletResponseWrapper{private PrintWriter tmpWriter;private StringWriter output;public CoverResponse(HttpServletResponse response) {super(response);output = new StringWriter(); tmpWriter = new PrintWriter(output);}public void finalize() throws Throwable { super.finalize(); output.close(); tmpWriter.close();}public String getContent() { tmpWriter.flush(); //重新整理該流的緩衝,詳看java.io.Writer.flush() String s = output.toString(); //此處可根據需要進行對輸出資料流以及Writer的重設操作 //比如tmpWriter.getByteArrayOutputStream().reset() return s; } //覆蓋getWriter()方法,使用我們自己定義的Writer public PrintWriter getWriter() throws IOException { return tmpWriter; } public void close() throws IOException { tmpWriter.close(); }}