天天看点

代理模式技术终结蔡徐坤

代理模式技术终结蔡徐坤

------敏感词过滤

  • 在开始进入正题之前,先来简述一下代理模式

    比如买戴尔电脑,有俩个选项,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() {
            //在服务器正常关闭时会执行
        }
    }