JavaWeb學習筆記9:Listener&Filter

1-Listener介紹與接口調用原理

Listener-監聽器:利用接口調用,監聽某一個事件的發生,狀態的改變
監聽器總共有8個,分成三種類型↓
一類:監聽作用域的創建和銷燬
二類:監聽作用域中屬性的創建銷燬和替換
三類:Session值的鈍化和活化(Activation)
接口調用:假設A類方法中的參數爲一個接口,而你在Test類中要調用A的方法,那麼只能通過編寫接口和實例化來調用A的方法
接口調用原理

2-Listener監聽三個作用域創建和銷燬

監聽器的新建要在web.xml中先配置
先回憶一下有哪幾個作用域以及作用域的對象是什麼:
1、pageContext - PageContext
2、request - HttpServletRequest
3、session - HttpSession
4、application - ServletContext
我們主要對下面2、3、4三個作用域進行監聽,每個作用域的監聽器對象其實就是在作用域對象名後+Listener

  • ServletContextListener
    servletcontext創建:
    啓動服務器的時候
    servletContext銷燬:
    關閉服務器、從服務器移除項目

  • 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 初始化了");
    	}
    }
    
  • HttpSessionListener
    session的創建
    只要有調用getSession就創建。 html:(沒有Session的調用) jsp:(默認調用getSession) servlet:(默認調用getSession)
    session的銷燬
    1、超時,30分鐘 2、非正常關閉,銷燬 3、正常關閉服務器(序列化)

    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了");
    	}
    }
    

    監聽器作用:
    利用它來,在作用域對象創建的時候
    1. 完成自己想要的初始化工作
    2. 執行自定義任務調度 執行某一個任務 Timer(定時器)

3-Listener監聽三個作用域屬性狀態變更

使用AttributeListener重寫並查看狀態變更
其中有屬性:添加(set)、替換(set:key一樣)、移出(remove)三種狀態

  • servletContext — ServletContextAttributeListene
    servletContext
  • request — ServletRequestAttributeListener
    request
  • session — HttpSessionAttributeListener
    session

HttpSessionBindingListener(比較少用,作用類似,就是看是否添加或移出屬性)
> 監聽對象與session綁定和解除綁定的動作

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

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

這裏有必要解釋一下HttpSessionBindingListener與HttpSessionAttributeListener的區別。
首先,兩者的作用類似,都是監聽對象的添加與解除,最大的區別就是,BindingListener要一個待監聽對象去實現這個接口,然後在Session中添加該對象的時候纔會觸發監聽器,但是如果你添加了其他對象,這個監聽器是不會被觸發的。
相反,AttributeListener也是要一個類去實現,在web.xml中配置要監聽的Session對象,注意是Session對象,也就是說,只要Session中無論添加了什麼對象,都會觸發這個監聽器,可以理解爲這是一個安檢門。

4-Listener監聽HttpSession鈍化活化

上面所說的兩種監聽器都必須在xml文件中進行註冊,而最後一種監聽器不需要註冊,只需要實現接口

HttpSessionActivationListener
用於監聽現在session的值是鈍化(序列化)還是活化(反序列化)的動作
1、鈍化 (序列化)
把內存中的數據 存儲到硬盤上
2、活化 (反序列化)
一定要實現Serializable接口 若已經鈍化,則重啓服務器就自動活化了 即把硬盤中的數據讀取到內存中

爲什麼要有鈍化活化?
Session中存放過多的值會增加內存負擔,所以我們可以把暫時不用的東西先鈍化,要用的時候活化
自動執行鈍化的事件默認是30分鐘,我們可以手動配置事件和路徑

如何配置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\helloworld
<Context>
	<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
		<Store className="org.apache.catalina.session.FileStore" directory="helloworld"/>
	</Manager>
</Context>
5-Filter介紹與簡單使用

Filter 其實就是對客戶端發出來的請求進行過濾,瀏覽器發出,然後服務器派servlet處理,在中間就可以過濾,其實過濾器起到的是攔截的作用
比如它可以做什麼?
  1. 對一些敏感詞彙進行過濾
  2. 統一設置編碼
  3. 自動登錄
  …

Filter的生命週期:在服務器加載該項目時創建,在服務器關閉或從服務器移除該項目時銷燬
Filter的執行順序:
 1、客戶端發出請求,先經過過濾器 如果過濾器放行,那麼才能到servlet
 2、如果有多個過濾器,則會按照註冊的映射順序來排隊,如果只有一個過濾器不放行,那麼後面排隊的過濾器以及servlet都不會受到請求


Filter的簡單使用:
filter1、定義一個類 實現Filter

public class FilterDemo implements Filter {
	public void destroy() {}
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		System.out.println("doFilter……");
		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的一些細節:
1、如果想放行,那麼在doFilter方法裏面操作,使用參數chain的
chain.doFilter(request, response);放行,讓請求到達下一個目標
2、<url-pattern>/*</url-pattern> 寫法格式與servlet一樣
  1. 全路徑匹配 以 / 開始
  2. 以目錄匹配 以 / 開始 以 * 結束
  3. 以後綴名匹配 以 * 開始 以後綴名結束
3、針對 dispatcher 設置
  REQUEST : 只要是請求過來,都攔截,默認就是REQUEST
  FORWARD : 只要是轉發都攔截
  ERROR : 頁面出錯發生跳轉
  INCLUDE : 包含頁面的時候就攔截

6-Filter實現自動登錄

1、案例分析
案例分析
2、搭建好數據庫(用戶信息),頁面(jsp)
3、AutoLoginFilter(主要代碼):

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
	try {
		//1.首先,無論用戶進入什麼頁面,先判斷用戶是否登陸並且沒關閉瀏覽器
		HttpServletRequest req = (HttpServletRequest) request;
		//如果已登錄且沒關閉瀏覽器,則自動放行
		if(req.getSession().getAttribute("user")!=null){
			chain.doFilter(request, response);
		}else{//session值不存在
			Cookie[] cookies = req.getCookies();
			Cookie cookie = CookieUtil.findCookie(cookies, "autologin");
			if(cookie!=null){//如果cookie存在,則說明用戶已經登錄過
				String value = cookie.getValue();
				String username = value.split("#")[0];
				String password = value.split("#")[1];
				UserDao dao = new UserDaoImpl();
				UserBean user = dao.login(username, password);
				req.getSession().setAttribute("user", user);
				chain.doFilter(request, response);
			}else{
				//cookie和session都不存在,直接放行要求登錄
				chain.doFilter(request, response);
			}
		}
	} catch (Exception e) {
		e.printStackTrace();
		chain.doFilter(request, response);
	}
}

4、LoginServlet(主要代碼):

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	try {
		String username = request.getParameter("username");
		String password = request.getParameter("password");
		String auto_login = "";
		auto_login+=request.getParameter("autologin");
		System.out.println(auto_login);
//			System.out.println(username+"=="+password+"=="+aotologin);
		UserDao dao = new UserDaoImpl();
		UserBean user = dao.login(username,password);
		if(user != null){
			//將user存儲到session中
			request.getSession().setAttribute("user", user);
			if(auto_login.equals("on")){
				//設置autologin的Cookie,包含賬號密碼,準備自動登錄
				Cookie autologin = new Cookie("autologin", (username+"#"+password));
				//設置最長存活時間
				autologin.setMaxAge(60*2);
				//設置保存路徑
				autologin.setPath(request.getContextPath());
				response.addCookie(autologin);
			}
			response.sendRedirect("index.jsp");
		}else{
			response.setContentType("text/html;charset=utf-8");
			response.getWriter().write("賬號或密碼錯誤!請重新登錄!");
			response.setHeader("refresh", "3;login.jsp");
		}
	} catch (SQLException e) {
		e.printStackTrace();
	}
}
HPF-自我總結

  第一次接觸監聽器尤其是過濾器的時候,對於這個自動登錄案例還不是理解的特別到位,但這次寫博客的時候,我對案例的代碼做了修改,而且針對修改過的代碼與原來的代碼做了比較,最後發現了問題所在。總而言之,希望對這兩個組件的理解能夠深刻記下!
  ——— 不積跬步,無以至千里;不積小流,無以成江海。

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