1. 程式人生 > 實用技巧 >JavaWeb - Filter過濾器、Listener監聽器

JavaWeb - Filter過濾器、Listener監聽器

1.Filter過濾器

  1. 作用:

    * 一般用於完成通過的操作。如:登入驗證、統一編碼處理、敏感字元的過濾。。。

  2. 快速入門

    1. 步驟:

      1. 定義一個類,實現介面Filter

      2. 複寫方法

      3. 配置攔截路徑

        1. web.xml

        2. 註解

package web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter(
"/*") //訪問資源之前,都會執行該過濾器 public class FilterDemo01 implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println(
"過濾器被執行了...."); //放行 filterChain.doFilter(servletRequest,servletResponse); } @Override public void destroy() { } }
demo01

  3. 過濾器細節

    1. web.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation
="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <filter> <filter-name>demo01</filter-name> <filter-class>web.filter.FilterDemo01</filter-class> </filter> <filter-mapping> <filter-name>demo01</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
web.xml

    2. 過濾器執行流程

      1. 執行過濾器

      2. 執行放行後的資源

      3. 回來執行過濾器放行程式碼下的程式碼

    3. 過濾器生命週期方法

    4. 過濾器配置詳解

      * 攔截路徑配置:

        1. 具體的資源路徑:/index.jsp 只有訪問index.jsp資源時,過濾器才會被執行

        2. 目錄攔截: / user / * 訪問/ user下的所有資源時,過濾器都會被執行

        3. 字尾名攔截:* . jsp 訪問所有後綴名為jsp資源時,過濾器都會被執行

        4. 攔截所有資源: / *

      * 攔截方式配置:資源被訪問的方式

        * 註解配置:

         * 設定dispatcherTypes屬性

          1. REQUEST:預設值。瀏覽器直接請求資源

          2. FORWARD:轉發訪問資源

          3. INCLUDE:包含訪問資源

          4. ERROR:錯誤跳轉資源

          5. ASYNV:非同步訪問資源

        web.xml配置:     

          * 設定<dispatcher></dispatcher>標籤即可

    5. 過濾器鏈(配置多個過濾器)

      * 執行順序:瀏覽器 - 過濾器1 - 過濾器2 - 資源執行 - 過濾器2 - 過濾器1 - 瀏覽器

      * 過濾器先後順序問題:

        1. 註解配置:按照類名的字串比較規則比較,值小的先執行

          * 如:AFilter 和 BFilter,AFilter先執行

        2. web.xml配置:<FilterMapping>誰定義在上面,誰先執行

  4. 案例1:登入驗證

    * 需求:

      1. 訪問某一資源頁面,驗證其是否登入,登入了直接放行

      2. 如果沒有登入,則跳轉到登入頁面,提示“您尚未登入,請先登入”。

package web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * 完成登入驗證的過濾器
 */
@WebFilter("/*")
public class LoginFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //0. 強制轉換
        HttpServletRequest request = (HttpServletRequest) req;
        //1. 獲取資源的請求路徑
        String uri = request.getRequestURI();

        //2. 判斷是否包含登入相關資源路徑,要注意排除掉 css/js/圖片/驗證碼等資源
        if(uri.contains("/login.jsp") || uri.contains("/loginServlet") || uri.contains("/css/") || uri.contains("/js/") || uri.contains("/fonts.") || uri.contains("/checkCodeServlet")){
            //包含,證明使用者就是想登入
            chain.doFilter(req,resp);
        }else {
            // 不包含,需要去驗證使用者是否登入
            //3. 從session中獲取user
            Object user = request.getSession().getAttribute("user");
            if(user != null){
                // 登陸了,放行
                chain.doFilter(req, resp);
            }else {
                // 沒有登入。跳轉登入頁面
                request.setAttribute("login_msg","您尚未登入,請登入");
                request.getRequestDispatcher("/login.jsp").forward(req,resp );
            }
        }
    }

    public void init(FilterConfig config) throws ServletException {

    }

    public void destroy() {
    }
}
登入過濾器實現

  5. 案例2:敏感詞彙過濾

    * 需求:

      1. 對錄入的資料進行敏感詞彙過濾

      2. 敏感詞彙參考(敏感詞彙.txt)

      3. 如果是敏感詞彙,替換為 ***

    * 分析:

      1. 對request物件進行增強。增強獲取引數的相關方法

      2. 放行,傳遞代理物件

    * 增強物件的功能:

      * 設計模式:一些通用的解決固定問題的方式

        * 裝飾模式

        * 代理模式:

          * 概念:

            1. 真實物件:被代理的物件

            2. 代理物件

            3. 代理模式:代理物件代理真實物件,來達到增強真實物件功能的目的

          * 實現方式:  

            1. 靜態代理:有一個類檔案來描述代理模式

            2. 動態代理:在記憶體中形成代理類

              * 實現步驟:

                1. 代理物件和真實物件實現相同的介面

                2. 代理物件 = Proxy.newProxyInstance();

                  三個引數:

                    1. 類載入器:真實物件 . getClass(). getClassLoader()

                    2. 介面陣列:真實物件 . getClass(). getInterfaces()

                    3. 處理器:new InvocationHandler()

                3. 使用代理物件呼叫方法:

                  * invoke 代理邏輯編寫的方法:代理物件呼叫的所有方法都會觸發該方法的執行

                    引數:

                      1. proxy:代理物件

                      2. method:代理物件呼叫的方法被封裝成的物件

                      3. args:代理物件呼叫的方法時,傳遞的實際引數

                4. 增強方式:      

                  1. 增強引數列表

                  2. 增強返回值型別

                  3. 增強方法體執行邏輯

package web.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. 動態代理增強Lenova

        SaleComputer proxy_lenovo = (SaleComputer) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() {
            /*
            invoke 代理邏輯編寫的方法:代理物件呼叫的所有方法都會觸發該方法的執行
              引數:
                1. proxy:代理物件
                2. method:代理物件呼叫的方法被封裝成的物件
                3. args:代理物件呼叫的方法時,傳遞的實際引數
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //判斷是否是sale方法
                if(method.getName().equals("sale")){
                    //1. 增強引數
                    double money = (double) args[0];
                    money = money * 0.85;
                    // 使用真實物件呼叫該方法
                    String obj = (String) method.invoke(lenovo, money);
                    //2. 增強返回值
                    return obj + "送滑鼠墊";
                }else {
                    Object obj = method.invoke(lenovo,args);
                    return obj;
                }
            }
        });

        String computer = proxy_lenovo.sale(8000);
        System.out.println(computer);
    }
}

package web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.BufferedReader;
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;

/**
 * 敏感詞彙過濾器
 */
@WebFilter("/*")
public class SensitiveWordsFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //1. 建立代理物件,增強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方法
                // 判斷是否是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);
            }
        });
        //2. 放行
        chain.doFilter(proxy_req, resp);
    }
    // 裝敏感詞彙的集合
    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 FileReader(realPath));

           // 將檔案的每一行資料新增到list中
           String line = null;
           while ((line = br.readLine())!=null){
               list.add(line);
           }
           br.close();
           System.out.println(list);
       }catch (Exception e){
           e.printStackTrace();
       }

    }

    public void destroy() {
    }
}
敏感詞彙過濾器實現

2. Listener:監聽器  

  * 概念:web的三大元件之。

    * 事件的監聽機制

      * 事件 : 一件事情

      * 事件源:事件發生的地啊

      * 監聽器:一個物件或者一段程式碼

      * 註冊監聽:將事件、事件源、監聽器繫結在一起。當事件源發生某個事件後,執行監聽器程式碼

  * ServletContextListener:監聽ServletContext物件的建立和銷燬

    * void contextDestroyed(ServletContextEvent sce):ServletContext物件被銷燬之前會呼叫該方法

    * void contextInitialized(ServletContextEvent sce):ServletContext物件建立後會呼叫該方法

  * 步驟:

    1. 定義一個類,實現ServletContextListener介面

    2. 複寫方法

    3. 配置

      1. web.xml

      2. 註解:@WebListener