JavaWeb-Filter & Listener

Listener & Filter

Listener

監聽器html

  • 能作什麼事?

監聽某一個事件的發生。 狀態的改變。java

  • 監聽器的內部機制

其實就是接口回調.web

接口回調

  • 需求:

A在執行循環,當循環到5的時候, 通知B。數據庫

事先先把一個對象傳遞給 A , 當A 執行到5的時候,經過這個對象,來調用B中的方法。 可是注意,不是直接傳遞B的實例,而是傳遞一個接口的實例過去。apache

Web監聽器

總共有8個 劃分紅三種類型瀏覽器

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

  2. 註冊 | 配置監聽器服務器

監聽三個做用域建立和銷燬

request  ---httpServletRequest
session  ---httpSession
aapplication  --- ServletContext

1. ServletContextListener

    servletcontext建立:

        1. 啓動服務器的時候

    servletContext銷燬:

        2. 關閉服務器. 從服務器移除項目


2. ServletRequestListener

    request建立:

        訪問服務器上的任意資源都會有請求出現。

        訪問 html: 會
        訪問 jsp: 會
        訪問 servlet : 會 


    request銷燬:

        服務器已經對此次請求做出了響應。


        public class MyRequestListener implements ServletRequestListener {
                @Override
                public void requestDestroyed(ServletRequestEvent sre) {
                    System.out.println("servletrequest 銷燬了");
                }

                @Override
                public void requestInitialized(ServletRequestEvent sre) {
                    System.out.println("servletrequest 初始化了");
                }
            }


          <listener>
            <listener-class>com.itheima.listener.MyRequestListener</listener-class>
          </listener>



3. HttpSessionListener

    session的建立
        只要調用getSession

        html:       不會
        jsp:        會     getSession();
        servlet:    會

    session的銷燬
        超時  30分鐘

        非正常關閉 銷燬

        正常關閉服務器(序列化)

        public class MySessionListener implements HttpSessionListener {

            @Override
            public void sessionCreated(HttpSessionEvent se) {
                System.out.println("建立session了");
            }

            @Override
            public void sessionDestroyed(HttpSessionEvent se) {
                System.out.println("銷燬session了");
            }
        }

做用:cookie

ServletContextListener

    利用它來,在servletcontext建立的時候, 
        1. 完成本身想要的初始化工做

        2. 執行自定義任務調度。 執行某一個任務。 Timer  

HttpSessionListener

    統計在線人數.

監聽三個做用域屬性狀態變動

能夠監聽在做用域中值 添加 | 替換 | 移除的動做。session

  • servletContext --- ServletContextAttributeListener 

  • request --- ServletRequestAttributeListener 

  • session --- HttpSessionAttributeListener 

監聽httpSession裏面存值的狀態變動

這一類監聽器不用註冊。

  • HttpSessionBindingListener

監聽對象與session 綁定和解除綁定 的動做

1. 讓javaBean 實現該接口便可

        @Override
        public void valueBound(HttpSessionBindingEvent event) {
            System.out.println("對象被綁定進來了");
        }

        @Override
        public void valueUnbound(HttpSessionBindingEvent event) {
            System.out.println("對象被解除綁定");
        }
  • HttpSessionActivationListener

用於監聽如今session的值 是 鈍化 (序列化)仍是活化 (反序列化)的動做

  • 鈍化 (序列化)

把內存中的數據 存儲到硬盤上

  • 活化 (反序列化)

把硬盤中的數據讀取到內存中。

  • session的鈍化活化的用意何在

session中的值可能會不少, 而且咱們有很長一段時間不使用這個內存中的值, 那麼能夠考慮把session的值能夠存儲到硬盤上【鈍化】,等下一次在使用的時候,在從硬盤上提取出來。 【活化】

  • 如何讓session的在必定時間內鈍化.

作配置便可

1. 在tomcat裏面 conf/context.xml 裏面配置

        對全部的運行在這個服務器的項目生效  

2. 在conf/Catalina/localhost/context.xml 配置

        對 localhost生效。  localhost:8080

3. 在本身的web工程項目中的 META-INF/context.xml

        只對當前的工程生效。

    maxIdleSwap : 1分鐘不用就鈍化
    directory :  鈍化後的那個文件存放的目錄位置。 

        D:\tomcat\apache-tomcat-7.0.52\work\Catalina\localhost\ListenerDemo\itheima

    <Context>
        <Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
            <Store className="org.apache.catalina.session.FileStore" directory="itheima"/>
        </Manager>
    </Context>

Filter

過濾器 , 其實就是對客戶端發出來的請求進行過濾。 瀏覽器發出, 而後服務器派servlet處理。 在中間就能夠過濾, 其實過濾器起到的是攔截的做用。

  • 做用

    1. 對一些敏感詞彙進行過濾
    2. 統一設置編碼
    3. 自動登陸

    ...

如何使用Filter

  1. 定義一個類, 實現Filter

    public class FilterDemo implements Filter {
    
        public void destroy() {
        }
    
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            System.out.println("來到過慮器了。。。");
            chain.doFilter(request, response);
        }
    
        public void init(FilterConfig fConfig) throws ServletException {
        }
    
    }
  2. 註冊過濾器

在web.xml裏面註冊,註冊的手法與servlet基本同樣。

<filter>
        <display-name>FilterDemo</display-name>
        <filter-name>FilterDemo</filter-name>
        <filter-class>com.itheima.filter.FilterDemo</filter-class>
      </filter>
      <filter-mapping>
        <filter-name>FilterDemo</filter-name>
        <url-pattern>/*</url-pattern>
      </filter-mapping>

Filter的生命週期

  • 建立

在服務器啓動的時候就建立。

  • 銷燬

服務器中止的時候。

Filter執行順序

  1. 客戶端發出請求,先通過過濾器, 若是過濾器放行,那麼才能到servlet

  2. 若是有多個過濾器, 那麼他們會按照註冊的映射順序 來 排隊。 只要有一個過濾器, 不放行,那麼後面排隊的過濾器以及我們的servlet都不會收到請求。

Filter細節:

  1. init方法的參數 FilterConfig , 能夠用於獲取filter在註冊的名字 以及初始化參數。 其實這裏的設計的初衷與ServletConfig是同樣的。

  2. 若是想放行,那麼在doFilter 方法裏面操做,使用參數 chain

    chain.doFilter(request, response); 放行, 讓請求到達下一個目標。
  3. <url-pattern>/*</url-pattern> 寫法格式與servlet同樣。

    1. 全路徑匹配 以 / 開始

      /LoginServlet
    2. 以目錄匹配 以 / 開始 以 * 結束

      /demo01/*

    3. 之後綴名匹配 以 * 開始 之後綴名結束

      *.jsp *.html *.do

  4. 針對 dispatcher 設置

    REQUEST : 只要是請求過來,都攔截,默認就是REQUEST 
    FORWARD : 只要是轉發都攔截。 
    ERROR : 頁面出錯發生跳轉 
    INCLUDE : 包含頁面的時候就攔截。

自動登陸

  • 需求分析

1. 搭建環境

  1. 搭建數據庫

  2. 搭建頁面

登陸servlet代碼

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    try {
        String userName = request.getParameter("username");
        String password = request.getParameter("password");
        String autoLogin = request.getParameter("auto_login");
        UserBean user = new UserBean();
        user.setUsername(userName);
        user.setPassword(password);

        UserDao dao = new UserDaoImpl();
        UserBean userBean = dao.login(user);

        if(userBean != null){
            //成功了,進入首頁
            request.getSession().setAttribute("userBean", userBean);
            response.sendRedirect("index.jsp");
        }else{
            //不成功...
            request.getRequestDispatcher("login.jsp").forward(request, response);
        }

    } catch (SQLException e) {
        e.printStackTrace();
    }
}

過濾器代碼

過濾器的核心不是完成攔截不給 , 仍是放行顯示。 它的核心是在放行以前,幫用戶完成登陸的功能。

  • 實現思路

  • 先判斷session是否有效, 若是有效,就不用取cookie了,直接放行。

  • 若是session失效了,那麼就取 cookie。

    1. 沒有cookie 放行

    2. 有cookie

      1. 取出來cookie的值,而後完成登陸
      2. 把這個用戶的值存儲到session中
      
      3. 放行。
      
      /**
       * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
       */
      public void doFilter(ServletRequest req, ServletResponse response, FilterChain chain) throws IOException, ServletException {
      
      try {
          HttpServletRequest request = (HttpServletRequest) req;
      
          //先判斷,如今session中還有沒有那個userBean.
          UserBean userBean = (UserBean) request.getSession().getAttribute("userBean");
          //還有,有效。
          if(userBean != null){
              chain.doFilter(request, response);
          }else{
              //表明session失效了。
      
              //2. 看cookie。
      
              //1. 來請求的時候,先從請求裏面取出cookie , 可是cookie有不少的key-value
              Cookie[] cookies = request.getCookies();
              //2. 從一堆的cookie裏面找出咱們之前給瀏覽器發的那個cookie
              Cookie cookie = CookieUtil.findCookie(cookies, "auto_login");
      
              //第一次來
              if(cookie  == null){
                  chain.doFilter(request, response);
              }else{
      
                  //不是第一次。
      
                  String value = cookie.getValue();
                  String username = value.split("#itheima#")[0];
                  String password = value.split("#itheima#")[1];
      
                  //完成登陸
                  UserBean user = new UserBean();
                  user.setUsername(username);
                  user.setPassword(password);
      
                  UserDao dao = new UserDaoImpl();
                  userBean = dao.login(user);
      
                  //使用session存這個值到域中,方便下一次未過時前還能夠用。
                  request.getSession().setAttribute("userBean", userBean);
      
                  chain.doFilter(request, response);
              }
      
          }
      
          } catch (Exception e) {
              e.printStackTrace();
              chain.doFilter(req, response);
          }
          }

BeanUtils的使用

BeanUtils.populate(bean, map);

//註冊本身的日期轉換器
        ConvertUtils.register(new MyDateConverter(), Date.class);


        //轉化數據
        Map map = request.getParameterMap();
        UserBean bean = new UserBean();

        轉化map中的數據,放置到bean對象身上
        BeanUtils.populate(bean, map);

總結

Listener

8個 

三種類型  
    針對三個做用域的建立和銷燬
    針對三個做用域的值改變 【添加 | 替換 | 移除】
    針對session中的值 【鈍化 活化】 , 【綁定  解綁】

鈍化 ( 序列化 ) 
    內存中的對象存儲到硬盤 

    超時失效。 session銷燬了。 

非正常關閉服務器, 鈍化  。 正常關閉服務器 銷燬

設置了session,多久時間。 context.xml


活化 (反序列化)
    從硬盤裏面讀取到內存

ServletContextListner : 應用被部署的時候, 服務器加載這個項目的時候,作一些初始化工做, 任務調度。 HttpSessionListener : 統計在線人數 HttpSessionActivationListener : 鈍化活化處理

Filter

使用頻率更高

  • 若是要寫一個過濾器。
  1. 定義一個類,實現接口 Filter

  2. 註冊 . web.xml . 與servlet類似。

  • 過濾器放行。

chain.doFilter(request, response);

  • 過濾器生命週期

    建立: 服務器加載這個項目的時候建立實例

    銷燬: 關閉服務器或者從服務器中移除項目的時候。

 

接口回調

package com.itheima.test;

/**
 * 1988年寫
 * @author xiaomi
 *
 */
public class A {
	

	public void print(B b){
		for (int i = 0; i < 10; i++) {
			System.out.println("循環到了--"+i);
			if(i == 5){
				System.out.println("循環到了5了,該通知B 了。");
				B b = new B();
				b.printFive();
			}
		}
	}
	
	

}
package com.itheima.test;

public class B {

	public void printFive(){
		System.out.println("A已經循環到了5, 因此B的這個方法將被調用");
	}
}
package com.itheima.test;

public class Test {

	public static void main(String[] args) {
		A a = new A();
		a.print();
	}
}

接口回調2

package com.itheima.test;

/**
 * 1988年寫的
 * @author xiaomi
 *
 */
public class A {

	/**
	 * 這是之前的java基礎使用的代碼。
	 * 可是假設這個A這個類是早在上個世紀80年 就寫好的A類, 這個方法 內部是不能直接new B()
	 * 1. 不能直接new B
	 * 
	 * 2. 頁不能傳遞B的實例進來。
	 * 
	 * 因此在定義這個方法的時候,無論將來寫的是B 類, 仍是C類,仍是D類, 人家爲了通用。
	 * 因此定義了一種接口,只要讓將來的那些類,實現這個接口。 而後這個方法的參數寫 接口類型便可。
	 */

	/*public void print(){
		for (int i = 0; i < 10; i++) {
			System.out.println("循環到了--"+i);
			if(i == 5){
				System.out.println("循環到了5了,該通知B 了。");
				B b = new B();
				b.printFive();
			}
		}
	}*/
	
	public void print(PrintListener listener){
		for (int i = 0; i < 10; i++) {
			System.out.println("我在1988年就開始打印這個語句了。。循環到了--"+i);
			if(i == 5){
				System.out.println("循環到了5了,該通知B 了。");
				listener.print();
				/*B b = new B();
				b.printFive();*/
			}
		}
	}
}
package com.itheima.test;

/**
 * 2018
 * @author xiaomi
 *
 */
public class B  implements PrintListener{

	/*public void printFive(){
		System.out.println("A已經循環到了5, 因此B的這個方法將被調用");
	}*/

	@Override
	public void print() {
		System.out.println("2018年。。。A已經循環到了5, 因此B的這個方法將被調用");
	}
}
package com.itheima.test;

/**
 * 1988年寫
 * 打印監聽器
 * @author xiaomi
 *
 */
public interface PrintListener {

	/**
	 * 一旦出現了某一種事件, 達到了某一個狀態,就調用這個方法。
	 */
	void print();
}
package com.itheima.test;

public class Test {

	public static void main(String[] args) {
		A a = new A();
		
		//這是多態的體現,
		
		/*
		 * 這個方法咋i1988年就定義了要收 printlistener 這個接口的類型。
		 * 在2018年的時候有一個類 B 實現了這個接口printlistener ,
		 * 因此如今能夠傳遞B進來
		 */
		a.print(new B());
	}
}
相關文章
相關標籤/搜索