代理模式技術終結蔡徐坤
------敏感詞過濾
-
在開始進入正題之前,先來簡述一下代理模式
比如買戴爾電腦,有倆個選項,1:從戴爾總部購買,2:從代理商處購買
現在把戴爾總部抽象為一個類,它實作了賣電腦的接口
package cm.boke; /** * @author long * @date 5/28/19 - 4:53 PM */ //定義賣電腦的接口 interface saleComputer{ public String sale(int money); } //戴爾實作賣電腦的接口 public class DaiEr implements saleComputer{ @Override public String sale(int money) { return "花了"+money+"元買了戴爾電腦"; } //寫一個main方法測試 public static void main(String[] args) { System.out.println(new DaiEr().sale(6000)); } }
運作結果 : 花了6000元買了戴爾電腦
雖然現在可以正常的賣電腦,但所謂"天高皇帝遠",僅僅在戴爾總部地區賣電腦市場有限,那麼
戴爾想要在全世界賣電腦則需要代理商.
抽象的來看,代理商一方面使得戴爾能在世界各地銷售,相當于加強了電腦的銷售功能;另一方
面,代理商需要賺取差價,從代理商處買電腦需要消費者支付更高的價格,這就相當于加強了買電腦
方法的參數;再來看,如果直接從總部買電腦,可能得到的隻是一台電腦,而從代理商處買電腦,會得到
一些配件或者贈品,相當于加強了方法的傳回值.
package cm.boke; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * @author long * @date 5/28/19 - 6:34 PM */ public class DaiLi { public static void main(String[] args) { //代理對象依賴于原對象,在使用代理對象之前要建立原對象 DaiEr dr = new DaiEr(); //獲得代理對象 /** * 該方法有三個參數,類加載器,原對象接口 * 最後一個參數裡寫邏輯 * 需要強制轉換為接口類型 */ saleComputer dl = (saleComputer) Proxy.newProxyInstance(dr.getClass().getClassLoader(), dr.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { /** * 上面的method就是目前的函數,args為參數清單 */ //下面倆行用來修改參數,即增強參數 int num = (int)args[0]; num*=0.85;//假定代理商克扣了百分之15的差價 return method.invoke(dr,num)+",并得到了贈品電腦配件"; } }); //使用代理 System.out.println(dl.sale(8000)); } }
運作結果 : 花了6800元買了戴爾電腦,并得到了贈品電腦配件
好,了解了上面的設計模式,我們就可以做一個攔截器,屏蔽蔡徐坤
基本原理是使用代理模式增強ServletRequest裡的getParameter方法
注釋标的很全,感興趣可以複制下來看
下面是最後的效果圖(圖形化界面是我自己寫的)
package cm; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.List; /** * @author long * @date 5/28/19 - 7:04 PM */ @WebFilter("/*") public class FilterCXK implements Filter { //建立一個List存放敏感詞 List<String> list = new ArrayList<>(); @Override public void init(FilterConfig filterConfig) throws ServletException { //該方法隻在伺服器啟動時執行一次 //加載檔案,檔案裡存放敏感詞 //沒有request對象,隻能通過filterConfig來擷取 ServletContext servletContext = filterConfig.getServletContext(); String realPath = servletContext.getRealPath("/WEB-INF/classes/cm/mgs.txt"); BufferedReader br = null; try{ br = new BufferedReader(new FileReader(realPath)); String temp; while (null != (temp = br.readLine())){ list.add(temp); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ if(null!=br){ try { br.close(); } catch (IOException e) { e.printStackTrace(); } } } } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { //這個方法在每次攔截時都會執行 ServletRequest proxyServlet = (ServletRequest) Proxy.newProxyInstance(servletRequest.getClass().getClassLoader(), servletRequest.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //如果是getParameter方法就驗證,不放行,如果是其他的方法就放行 if(method.getName().equals("getParameter")){ String msg = (String) method.invoke(servletRequest,args); //周遊敏感詞集合 for (String temp:list) { //如果找到敏感詞就替換為*** if(msg.contains(temp)){ System.out.println("執行了"); msg = msg.replaceAll(temp,"***"); } } return msg; }else{ return method.invoke(servletRequest,args); } } }); //放行代理對象 filterChain.doFilter(proxyServlet,servletResponse); } @Override public void destroy() { //在伺服器正常關閉時會執行 } }