思路:客戶端請求服務器數據,經過Filter過濾(請求放行,響應攔截),服務器向客戶端返回數據時,在Filter中修改掉返回數據中違法的部分。
修改服務器的響應需要自定義一個HttpServletResponse的包裝類,繼承自HttpServletResponseWrapper即可實現自己的HttpServletResponse的包裝類。
大概是這樣的:
//package com.ecshop.tools; import java.io.CharArrayWriter; import java.io.InputStream; import java.io.PrintWriter; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; public class ShieldKeywordResponseWrapper extends HttpServletResponseWrapper{ private CharArrayWriter caw; private PrintWriter pw; public ShieldKeywordResponseWrapper(HttpServletResponse response) { super(response); // 這個是我們保存返回結果的地方 caw = new CharArrayWriter(); // 這個是包裝PrintWriter的,讓所有結果通過這個PrintWriter寫入到caw中 pw = new PrintWriter(caw); } @Override public PrintWriter getWriter() { return pw; } public String getResult() { return caw.toString(); } }
因為違法關鍵詞都包含在響應文本消息中,服務器向請求客戶端響應文本消息必須獲取HttpServletResponse對象中的PrintWriter文本輸出流對象進行輸出消息,所以我們的這個封裝類覆蓋HttpServletResponse的getWriter是很重要的一步,我這個封裝類的意思是讓服務器響應數據時使用我們修改過的PrintWriter文本輸出流,輸出的數據並不立刻響應給客戶,而是把輸出的數據都保留在了CharArrayWriter這個對象中,當控制層執行完畢我們就可以在Filter中進行獲取CharArrayWriter對象中的數據進行修改了,修改完畢我們在返回給你客戶,就是我們想要的效果了。(而默認HttpServletResponse的PrintWriter對象是由tomcat自己所擴展自PrintWriter的CoyoteWriter對象,CoyoteWriter對象所打印的數據都保留在OutputBuffer對象(也是tomcat自己所擴展自Writer的一個對象)中,我們不方便獲取它的文本數據,所以我們修改掉它,當OutputBuffer執行flush就發送消息,或者不執行讓servlet結束后自動發送消息)。
以上是我看了一點tomcat源碼然后瞎推理,對不對無所謂。。
當我們HttpServletResponse的包裝類弄完剩下的就好辦了。
//我們看下過濾器中的doFilter函數部分代碼就足夠了 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse res= (HttpServletResponse) response; //我們剛剛做的包裝類在這里 ShieldKeywordResponseWrapper skrw= new ShieldKeywordResponseWrapper(res); chain.doFilter(request, skrw); //在servlet處理完畢后我們開始做處理 String result = skrw.getResult(); //替換關鍵詞為* Properties p = new Properties(); p.load(ShieldKeywords.class.getResourceAsStream("/keywords.properties")); Set<Entry<Object, Object>> se= p.entrySet(); for(Entry<Object, Object> e:se){ result = result.replace(String.valueOf(e.getKey()), String.valueOf(e.getValue())); } // 輸出最終的結果 PrintWriter out = response.getWriter(); out.write(result); //以下兩句無作用,CharArrayWriter中為空函數,tomcat自己提供的OutputBuffer執行這兩句才有作用 out.flush(); out.close(); }
最后看下keywords.properties文件的內容:
違法詞1=*
違法詞2=*
建議web.xml中過濾器配置時只映射響應文本數據的請求url,因有的請求是要獲取一個文件流,服務器HttpServletResponse響應時文本輸出流和字節流是沖突的,正常情況下兩者只可取一,不然會報錯