動態代理的分析以及利用動態代理模式進行敏感詞彙過濾

動態代理

增強對象的功能:

  • 設計模式:一些通用的解決固定問題的方式
  • 代理模式
  • 概念:
    (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=你個笨蛋,你個大壞蛋

同時控制檯輸出以下內容,就會將敏感詞彙替換掉

張三:你個***,你個大***
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章