动态代理的分析以及利用动态代理模式进行敏感词汇过滤

动态代理

增强对象的功能:

  • 设计模式:一些通用的解决固定问题的方式
  • 代理模式
  • 概念:
    (1). 真实对象:被代理的对象
    (2). 代理对象:
    (3). 代理模式:代理对象代理真实对象,达到增强真实对象功能的目的
  • 实现方式:
    (1). 静态代理:有一个类文件描述代理模式
    (2). 动态代理:在内存中形成代理类
  • 动态代理实现步骤:
    ①. 代理对象和真实对象实现相同的接口
    ②. 代理对象 = Proxy.newProxyInstance();
    ③. 使用代理对象调用方法。
    ④. 增强方法

对于代理模式,我们可以举一个简单的例子,例如我们要买一台联想的电脑,之前我们是需要向联想厂家购买的,那么现在有代理商,我们可以通过代理商来购买联想电脑。

首先创建一个接口SaleComputer,定义sale和show方法。

package cn.itcast.proxy;

public interface SaleComputer {
    public String sale(double money);

    public void show();
}

其次,我们创建一个真实类Lenovo。

package cn.itcast.proxy;
/**
 * 真实类
 */
public class Lenovo implements SaleComputer {

    @Override
    public String sale(double money) {

        System.out.println("花了"+money+"元买了一台联想电脑...");
        return "联想电脑";
    }
    @Override
    public void show() {
        System.out.println("展示电脑...");
    }
}

接下来,我们通过创建ProxyTest类来演示,

package cn.itcast.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyTest {

    public static void main(String[] args) {
        //1.创建真实对象
        Lenovo lenovo = new Lenovo();
        //2.动态代理增强lenovo对象
        /*
            三个参数:
                1. 类加载器:真实对象.getClass().getClassLoader()
                2. 接口数组:真实对象.getClass().getInterfaces()
                3. 处理器:new InvocationHandler()
                代理对象proxy_lenovo为Object对象,因为代理对象和真实对象实现相同的接口,所以将其强行转换为SaleComputer接口类型
         */
        SaleComputer proxy_lenovo = (SaleComputer) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() {
            /*
                代理逻辑编写的方法:代理对象调用所有方法都会触发该方法执行。
                参数:
                    1.proxy:代理对象
                    2.method:代理对象调用的方法,被封装为的对象 -->sale
                    3.args:代理对象调用的方法时,传递实际参数 -->8000.0
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("该方法执行了...");
                return null;
            }
        });

        //3.调用方法,用代理对象调用
        String computer = proxy_lenovo.sale(8000);
        System.out.println(computer);
    }
}

控制台输出一内容,表明代理对象调用方法会触发invoke方法的执行。

该方法执行了...
null

我们在ProxyTest再调用show类,同样也是可以触发invoke方法执行。

proxy_lenovo.show();

通过上面控制台的输出的null,可以看出调用的sale方法,并没有被调用;也就是说明代理商并没有卖电脑的功能,只是增强联想厂家卖电脑的功能
因此我们要想让其调用,我们可以在invoke方法里面使用真实对象调用

//使用真实对象调用该方法
Object obj = method.invoke(lenovo, args);
return obj;//obj会传递到proxy_lenovo.sale方法执行完后的返回值computer

我们再次运行,我可以通过控制台的输出内容,了解到sale方法被调用了

该方法执行了...
花了8000.0元买了一台联想电脑...
联想电脑

在现实生活中,我们作为买家要花8000元买电脑+鼠标垫(赠品),那么代理商需要抽取一部分费用,假如代理上抽取15%的费用,用85%的费用向厂家购买电脑。
对于上面的这种情况,我们可以通过增强方式在invoke方法中实现,
增强方式:
①. 增强参数列表
②. 增强返回值类型
③. 增强方法体执行逻辑

			@Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("该方法执行了...");

                //判断是否是sale方法
                if (method.getName().equals("sale")){
                    //1.增强参数
                    double money = (double) args[0];
                    money = money * 0.85;
                    System.out.println("专车接...");
                    //使用真实对象调用该方法
                    String obj = (String) method.invoke(lenovo, money);

                    System.out.println("送货到家...");

                    //2. 增强返回值
                    return obj+"_鼠标垫 ";

                }else {
                    Object obj = method.invoke(lenovo, args);
                    return obj;
                }
            }
        });

控制台输出为:(其中6800元只是代理商向厂家付的费用)

该方法执行了...
花了6800.0元买了一台联想电脑...
送货到家...
联想电脑_鼠标垫 

利用动态代理模式进行敏感词汇过滤

一、需求:

  1. 敏感词汇参考《敏感词汇.txt》,其内容如下:
笨蛋
坏蛋
  1. 如果是敏感词汇,替换为 ***

二、分析:
1. 对request对象进行增强。增强获取参数相关方法
2. 放行。传递代理对象

创建SensitiveWordsFilter将request请求对象中的敏感词汇替换,然后封装到新的request对象中,选择使用增强返回值类型方法的代理模式来实现;需要注意《敏感词汇.txt》文件导入的路径要配置正确。

package cn.itcast.web.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

/**
 * 敏感词汇过滤器
 */
@WebFilter("/*")
public class SensitiveWordsFilter implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        // 1.创建代理对象,增强request的getParameter方法
        ServletRequest proxy_req = (ServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 增强getParameter方法
                if (method.getName().equals("getParameter")){
                    // 增强返回值
                    String value = (String) method.invoke(req, args);
                    if (value != null){
                        for(String str : list){
                            if(value.contains(str)){
                                value = value.replaceAll(str, "***");
                            }
                        }
                    }
                    return value;
                }
                return method.invoke(req, args);
            }
        });

        chain.doFilter(proxy_req, resp);
    }
    private List<String> list = new ArrayList<String>();    //敏感词汇集合

    public void init(FilterConfig config) throws ServletException {
        try {
            // 获取文件的真实路径
            ServletContext servletContext = config.getServletContext();
            String realPath = servletContext.getRealPath("/WEB-INF/classes/敏感词汇.txt");
            // 读取文件
            BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(realPath),"utf-8"));
            // 将文件的每一行添加到list集合中
            String line = null;
            while((line = br.readLine()) != null){
                list.add(line);
            }
            br.close();
            System.out.println(list);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

创建一个TestServlet类

package cn.itcast.web.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/TestServlet")
public class TestServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String name = request.getParameter("name");
        String msg = request.getParameter("msg");

        System.out.println(name + ":" + msg);

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

在浏览器输入以下内容,进行访问

http://localhost:8080/demo_filter_listener/TestServlet?name=张三&msg=你个笨蛋,你个大坏蛋

同时控制台输出以下内容,就会将敏感词汇替换掉

张三:你个***,你个大***

你可能感兴趣的:(JavaWEB基础)