Filter和Listener相關學習筆記

Filter:過濾器

  • 概念
    • 當訪問服務器的資源時,過濾器可以將請求攔截下來,完成一些特殊的功能。
    • 一般用於完成通用的操作。(如:登錄驗證、統一編碼處理、敏感字符過濾…)
  • 步驟
    1. 定義一個類,實現接口Filter
    2. 複寫方法
    3. 配置攔截路徑
      1. web.xml
      2. 註解
@WebFilter("/*")	//訪問所有資源之前都會執行該過濾器
public class FilterDemo implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //對request對象請求消息增強
        System.out.println("FilterDemo被執行了。。。。");
        
        filterChain.doFilter(servletRequest,servletResponse);//放行
        
        //對response對象的響應消息增強
        System.out.println("FilterDemo回來了。。。。");
    }

    @Override
    public void destroy() {}
}

過濾器細節

web.xml配置

<filter>
	<filter-name>demo1</filter-name>
	<filter-class>cn.comany.web.filter.FilterDemo</filter-class>
</filter>
<filter-mapping>
	<filter-name>demo</filter-name>
	<!-- 攔截路徑 -->
	<url-pattern>/*</url-pattern>
</filter-mapping>

過濾器執行流程

  1. 執行過濾器
  2. (放行)執行放行後的資源
  3. 回來執行過濾器放行代碼下邊的代碼

過濾器生命週期方法

  1. init:在服務器啓動後,會創建Filter對象,然後調用init方法。(只執行一次,用於加載資源)
  2. doFilter:每一次請求被攔截資源時,會執行。(執行多次)
  3. destroy:在服務器關閉後,Filter對象被銷燬。如果服務器是正常關閉,則會執行destroy方法。(只執行一次,用於釋放資源)

過濾器配置詳解

攔截路徑配置
  • 具體資源路徑:/index.jsp 只有訪問 index.jsp 資源時,過濾器纔會被執行
  • 攔截目錄:/user/* 訪問 /user 下的資源時,過濾器會被執行
  • 後綴名攔截:*.jsp 訪問後綴名爲 jsp 資源時,過濾器會被執行
  • 攔截所有資源:/* 訪問任何資源,過濾器都會被執行
攔截方式配置:資源被訪問的方式
註解配置
  • 設置dispatcherTypes屬性
    • REQUEST:默認值。瀏覽器直接請求資源
    • FORWARD:轉發訪問資源
    • INCLUDE:包含訪問資源
    • ERROR:錯誤跳轉資源
    • ASYNC:異步訪問資源
//瀏覽器直接請求index.jsp資源時會被執行
@WebFilter(value="/index.jsp",dispatcherTypes=DispatcherType.REQUEST)
//只有轉發訪問index.jsp時,該過濾器纔會被執行
@WebFilter(value="/index.jsp",dispatcherTypes=DispatcherType.FORWARD)
//瀏覽器直接請求index.jsp 或 轉發訪問index.jsp時,該過濾器纔會被執行
@WebFilter(value="/index.jsp",dispatcherTypes={DispatcherType.REQUEST,DispatcherType.FORWARD})
public class FilterDemo 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("FilterDemo被執行了。。。。");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {}
}
web.xml配置
  • 設置 <dispatcher></dispatcher> 標籤即可

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

  • 執行順序:如果有兩個過濾器(過濾器1和過濾器2)
    1. 過濾器1
    2. 過濾器2
    3. 資源執行
    4. 過濾器2
    5. 過濾器1
  • 過濾器先後順序問題:
    • 註解配置:按照類名的字符串比較規則比較,值小的先執行
      • 如: AFilter 和 BFilter,AFilter就先執行了。
    • web.xml配置:<filter-mapping> 誰定義在上邊,誰先執行

增強對象的功能

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

裝飾模式

代理模式

  • 概念
    • 真實對象:被代理的對象
    • 代理對象:代理真實對象
    • 代理模式:代理對象代理真實對象,達到增強真實對象功能的目的
實現方式
  • 靜態代理:有一個類文件描述代理模式
  • 動態代理:在內存中形成代理類
    • 實現步驟:
      1. 代理對象和真實對象實現相同的接口
      2. 代理對象 = Proxy.newProxyInstance();
      3. 使用代理對象調用方法
      4. 增強方法
    • 增強方式
      • 增強參數列表
      • 增強返回值類型
      • 增強方法體執行邏輯
//真實類
public class Phone implements SalePhone {
    @Override
    public String sale(double money){
        System.out.println("花"+money+"買了一部手機");
        return "XX手機";
    }
    @Override
    public void show(){
        System.out.println("很開心");
    }
}

public class ProxyTest {
    public static void main(String[] args) {
        //1.創建真實對象
        Phone phone = new Phone();
        //2.動態代理增強Phone對象
        /*
         * 三個參數:
         * 1.類加載器:真實對象.getClass().getClassLoader()
         * 2.接口數組:真實對象.getClass().getInterfaces()
         * 3.處理器:new InvocationHandler()
         * */
        SalePhone proxyPhone = (SalePhone) Proxy.newProxyInstance(phone.getClass().getClassLoader(), phone.getClass().getInterfaces(), new InvocationHandler() {
            /*
             * 代理邏輯編寫的方法:代理對象調用的所有方法都會觸發該方法執行
             * 參數:
             *   1.proxy:代理對象
             *   2.method:代理對象調用的方法,被封裝爲的對象
             *   3.args:代理對象調用方法時,傳遞的實際參數
             * */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                /*
                System.out.println(method.getName());	//proxyPhone.show();代理對象調用該方法輸出show
                System.out.println(args[0]);	//proxyPhone.sale(8000);代理對象調用該方法輸出8888
                */
                //判斷是否是sale方法
                if (method.getName().equals("sale")) {
                    //1.增強參數
                    double money = (double) args[0];
                    money *= 0.85;
                    //使用真實對象調用該方法
                    String obj = (String) method.invoke(phone, money);
                    //2.增強返回值
                    return obj + "_耳機";
                } else {
                    Object obj = method.invoke(phone, args);
                    return obj;
                }
            }
        });
        //2.調用方法
        String newPhone = proxyPhone.sale(8888);
        System.out.println(newPhone);
        proxyPhone.show();	//調用代理的對象
    }
}

Listener:監聽器

  • 概念:web的三大組件之一。
    • 事件監聽機制
      • 事件:一件事情
      • 事件源:事件發生的地方
      • 監聽器:一個對象
      • 註冊監聽:將事件、事件源、監聽器綁定在一起。 當事件源上發生某個事件後,執行監聽器代碼。

ServletContextListener

  • 監聽ServletContext對象的創建和銷燬

  • 方法

    • void contextDestroyed(ServletContextEvent sce):ServletContext對象被銷燬之前會調用該方法
    • void contextInitialized(ServletContextEvent sce):ServletContext對象創建後會調用該方法
  • 步驟

    1. 定義一個類,實現ServletContextListener接口

    2. 複寫方法

    3. 配置

      1.web.xml

      <listener>
      	<listener-class>cn.company.web.listener.ContextLoaderListener</listener-class>
      </listener>
      <!-- 指定初始化參數 -->
      <context-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>/WEB-INF/classes/applicationContext.xml</param-value>
      </context-param>
      

      2.註解:@WebListener

@WebListener
public class ContextLoaderListener implements ServletContextListener {
    /*
    * 監聽ServletContext對象創建的。ServletContext對象服務器啓動後自動創建
    * 在服務器啓動後自動調用
    * */
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        //加載資源文件
        //1.獲取ServletContext對象
        ServletContext servletContext = servletContextEvent.getServletContext();
        //2.加載資源文件
        String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation");
        //3.獲取真實路徑
        String realPath = servletContext.getRealPath(contextConfigLocation);
        //4.加載進內存
        try {
            FileInputStream fis = new FileInputStream(realPath);
            System.out.println(fis);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("ServletContext對象被創建了。。。");
    }

    /*
    * 在服務器關閉後,ServletContext對象被銷燬。當服務器正常關閉後該方法被調用
    * */
    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {System.out.println("ServletContext對象被銷燬了。。。");}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章