天天看點

代理模式技術終結蔡徐坤

代理模式技術終結蔡徐坤

------敏感詞過濾

  • 在開始進入正題之前,先來簡述一下代理模式

    比如買戴爾電腦,有倆個選項,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() {
            //在伺服器正常關閉時會執行
        }
    }