很多網(wǎng)站都需要對于某些關(guān)鍵字或者某些敏感詞匯進行過濾替換的功能。比如在輸入框中輸入些js 腳本,或者輸入些政府類型的詞匯等都是不允許的,但是你不能限制用戶的自由。所以對于網(wǎng)站的過濾功能就顯得很有必要了。對于一般的網(wǎng)站使用來說,不需要非常復(fù)雜的過濾算法等比較高端的實現(xiàn)。簡單的用 filter 和 HttpServletRequestWrapper 就可以實現(xiàn)。
HttpServletRequestWrapper 的實現(xiàn)采用了包裝模式,具體介紹請另找資料。直接切入正題。實現(xiàn)思路:首先定義一個 properties文件,在文件中存放需要替換的文字和替換后的文字,比如替換 fuck=** ,政府 =** ,替換 <=< 和 >=> (這樣就可以避免文本輸入的 js 腳本)。然后定義一個類來繼承 HttpServletRequestWrapper 達到包裝 request對象的作用,最后用一個 filter 使用包裝后的 request 對象(即已經(jīng)經(jīng)過了過濾作用)。
keyword.properties文件:
CNM=**?? fuck=**?? <=<?? >=>
然后寫一個操作properties文件的工具類,PropertiesUtil.java
package?com.lhwl.elt.filter; import?java.io.File; import?java.io.FileInputStream; import?java.io.InputStream; import?java.util.Enumeration; import?java.util.HashMap; import?java.util.Iterator; import?java.util.Map; import?java.util.Properties; import?java.util.Set; public?class?PropertiesUtil{ public?static?Map?readProperties(String?src)?{ Properties?props?=?new?Properties(); Map?map?=?new?HashMap(); try?{ File?file=new?File(src); InputStream?in=new?FileInputStream(file); props.load(in); Enumeration?en?=?props.propertyNames(); while?(en.hasMoreElements())?{ String?key?=?(String)?en.nextElement(); String?value?=?props.getProperty(key); map.put(key,?value);//把properties文件中的key-value存放到一個map中 } return?map; }?catch?(Exception?e)?{ e.printStackTrace(); } return?null; } public?static?String?replaceCheck(Map?map,String?name)?{ Setkeys?=?map.keySet(); Iteratoriter?=?keys.iterator(); while?(iter.hasNext())?{ String?key?=?iter.next(); String?value?=?(String)?map.get(key); if?(name.contains(key))?{ name=name.replace(key,?value);//對于符合map中的key值實現(xiàn)替換功能 } } return?name; } }
這里我把從properties文件中讀取的key--value的形式都存放到一個map對象中,方法都用static關(guān)鍵字,方便調(diào)用。
? ? 然后寫了個KeyWordRequestWrapper來繼承HttpServletRequestWrapper,實現(xiàn)包裝request對象的作用。
package?com.lhwl.elt.filter; import?java.util.Iterator; import?java.util.Map; import?java.util.Set; import?javax.servlet.http.HttpServletRequest; import?javax.servlet.http.HttpServletRequestWrapper; public?final?class?KeyWordRequestWrapper?extends?HttpServletRequestWrapper{ public?Map?keyMap; public?KeyWordRequestWrapper(HttpServletRequest?servletRequest,Map?keyMap){ super(servletRequest); this.keyMap?=?keyMap; } @Override public?Map?getParameterMap()?{ super.getContextPath(); Mapmap?=?super.getParameterMap(); if(!map.isEmpty()){ SetkeySet?=?map.keySet(); IteratorkeyIt?=?keySet.iterator(); while(keyIt.hasNext()){ String?key?=?keyIt.next(); // String?value?=?map.get(key)[0]; // map.get(key)[0]?=?this.replaceParam(value); //這邊實現(xiàn)對整個數(shù)組的判斷。 String[]?values=map.get(key); for(int?i=0;i<values.length;i++){ map.get(key)[i]=this.replaceParam(values[i]); } } } return?map; } /* @Override public?String[]?getParameterValues(String?name)?{ //?TODO?Auto-generated?method?stub String[]?resources?=?super.getParameterValues(name);? if?(resources?==?null)? return?null;? int?count?=?resources.length;? String[]?results?=?new?String[count];? for?(int?i?=?0;?i?<?count;?i++)?{? results[i]?=?this.replaceParam(resources[i]);? }? return?results;? }*/ public?String?replaceParam(String?name){ return?PropertiesUtil.replaceCheck(keyMap,name); } }
這里由于本人項目的框架原因,框架的request都是使用的getParameterMap來獲取的,經(jīng)過處理了,所以沒有使用 getParameterValues,可以看到代碼中注釋掉的方法。覆寫了ServletRequestWrapper中的 getParameterMap方法來實現(xiàn)包裝功能,一般情況下,提交的value數(shù)組都只有一個,String value = map.get(key)[0];map.get(key)[0] = this.replaceParam(value);即可滿足要求,但為了不出情況,還是實現(xiàn)了對整個數(shù)組的過濾替換功能。
?? 還剩個filter來實現(xiàn)了,先看具體的filter代碼:
package?com.lhwl.elt.filter; import?java.io.IOException; import?java.util.HashMap; import?javax.servlet.Filter; import?javax.servlet.FilterChain; import?javax.servlet.FilterConfig; import?javax.servlet.ServletException; import?javax.servlet.ServletRequest; import?javax.servlet.ServletResponse; import?javax.servlet.http.HttpServletRequest; public?class?KeyWordFilter?implements?Filter{ private?FilterConfig?filterConfig; public?static?HashMap?keyMap?=?null; public?static?String?path; @Override public?void?init(FilterConfig?filterConfig)?throws?ServletException?{ this.filterConfig=filterConfig; String?keyWordPath?=?filterConfig.getInitParameter("key"); path?=?filterConfig.getServletContext().getRealPath(keyWordPath); } @Override public?void?doFilter(ServletRequest?request,?ServletResponse?response,? FilterChain?chain)?throws?IOException,?ServletException?{ HttpServletRequest?req?=?(HttpServletRequest)request; if(keyMap?==?null){ keyMap?=?(HashMap)PropertiesUtil.readProperties(path); } if(req.getMethod().equals("POST")){ chain.doFilter(new?KeyWordRequestWrapper(req,keyMap),?response); }else{ chain.doFilter(request,?response); } } @Override public?void?destroy()?{ this.filterConfig?=?null;? } }
這里在filter初始化的時候,就獲得項目的真實路徑,然后把最先定義的keyword.properties文件放到WEB-INF目錄下,定義一個 keyWordPath,然后就可以通過在web.xml文件中配置init-param來注入。這里把keyMap和path都定義為static,這 樣只需要在加載的時候一次初始化就好了。chain.doFilter(new KeyWordRequestWrapper(req,keyMap), response);對于需要過濾的內(nèi)容進行處理關(guān)鍵字,敏感字等,其他的則正常chain.doFilter(request, response); 最后再web.xml中配置這個filter就可以,注意配置的順序不要和其他filter沖突就行。web.xml配置:
keyWordFiltercom.lhwl.elt.filter.KeyWordFilterkey/WEB-INF/keyword.propertieskeyWordFilter/*
OK,現(xiàn)在只要輸入些properties文件中定義好要替換的內(nèi)容,則自動的實現(xiàn)了替換功能。比如輸入fuck,提交顯示出來的就變成了**,對輸入的一些js腳本也能夠當(dāng)成文本顯示出來了。。。