快速學(xué)習(xí)JavaWeb中監(jiān)聽(tīng)器(Listener)的使用方法
一、監(jiān)聽(tīng)器介紹
1.1、監(jiān)聽(tīng)器的概念
監(jiān)聽(tīng)器是一個(gè)專門用于對(duì)其他對(duì)象身上發(fā)生的事件或狀態(tài)改變進(jìn)行監(jiān)聽(tīng)和相應(yīng)處理的對(duì)象,當(dāng)被監(jiān)視的對(duì)象發(fā)生情況時(shí),立即采取相應(yīng)的行動(dòng)。監(jiān)聽(tīng)器其實(shí)就是一個(gè)實(shí)現(xiàn)特定接口的普通java程序,這個(gè)程序?qū)iT用于監(jiān)聽(tīng)另一個(gè)java對(duì)象的方法調(diào)用或?qū)傩愿淖儯?dāng)被監(jiān)聽(tīng)對(duì)象發(fā)生上述事件后,監(jiān)聽(tīng)器某個(gè)方法立即被執(zhí)行。
1.2、監(jiān)聽(tīng)器案例——監(jiān)聽(tīng)window窗口的事件監(jiān)聽(tīng)器
package me.gacl.listener.demo; import java.awt.Frame; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; public class Demo1 { /** *java的事件監(jiān)聽(tīng)機(jī)制 *1、事件監(jiān)聽(tīng)涉及到三個(gè)組件:事件源、事件對(duì)象、事件監(jiān)聽(tīng)器 *2、當(dāng)事件源上發(fā)生某一個(gè)動(dòng)作時(shí),它會(huì)調(diào)用事件監(jiān)聽(tīng)器的一個(gè)方法,并在調(diào)用該方法時(shí)把事件對(duì)象傳遞進(jìn)去, * 開(kāi)發(fā)人員在監(jiān)聽(tīng)器中通過(guò)事件對(duì)象,就可以拿到事件源,從而對(duì)事件源進(jìn)行操作。 */ public static void main(String[] args) { Frame f = new Frame(); f.setSize(400, 400); f.setVisible(true); //注冊(cè)事件監(jiān)聽(tīng)器 f.addWindowListener(new WindowListener(){ public void windowActivated(WindowEvent e) { } public void windowClosed(WindowEvent e) { } /** * 當(dāng)window窗體關(guān)閉時(shí)就會(huì)WindowListener這個(gè)監(jiān)聽(tīng)器監(jiān)聽(tīng)到, * 監(jiān)聽(tīng)器就會(huì)調(diào)用windowClosing方法處理window窗體關(guān)閉時(shí)的動(dòng)作 */ public void windowClosing(WindowEvent e) { //通過(guò)事件對(duì)象e來(lái)獲取事件源對(duì)象 Frame f = (Frame) e.getSource(); System.out.println(f+"窗體正在關(guān)閉"); f.dispose(); } public void windowDeactivated(WindowEvent e) { } public void windowDeiconified(WindowEvent e) { } public void windowIconified(WindowEvent e) { } public void windowOpened(WindowEvent e) { } }); } }
1.3、設(shè)計(jì)一個(gè)可以被別的對(duì)象監(jiān)聽(tīng)的對(duì)象
我們平時(shí)做開(kāi)發(fā)的時(shí)候,我們是寫(xiě)監(jiān)聽(tīng)器去監(jiān)聽(tīng)其他對(duì)象,那么我們?nèi)绻朐O(shè)計(jì)一個(gè)對(duì)象,讓這個(gè)對(duì)象可以被別的對(duì)象監(jiān)聽(tīng)又該怎么做呢,可以按照嚴(yán)格的事件處理模型來(lái)設(shè)計(jì)一個(gè)對(duì)象,這個(gè)對(duì)象就可以被別的對(duì)象監(jiān)聽(tīng),事件處理模型涉及到三個(gè)組件:事件源、事件對(duì)象、事件監(jiān)聽(tīng)器。
下面我們來(lái)按照事件處理模型來(lái)設(shè)計(jì)一個(gè)Person對(duì)象,具體代碼如下:
package me.gacl.observer; /** * @ClassName: Person(事件源) * @Description: 設(shè)計(jì)一個(gè)Person類作為事件源,這個(gè)類的對(duì)象的行為(比如吃飯、跑步)可以被其他的對(duì)象監(jiān)聽(tīng) * @author: 孤傲蒼狼 * @date: 2014-9-9 下午9:26:06 * */ public class Person { /** * @Field: listener * 在Person類中定義一個(gè)PersonListener變量來(lái)記住傳遞進(jìn)來(lái)的監(jiān)聽(tīng)器 */ private PersonListener listener; /** * @Method: eat * @Description: 設(shè)計(jì)Person的行為:吃 * @Anthor:孤傲蒼狼 * */ public void eat() { if (listener != null) { /** * 調(diào)用監(jiān)聽(tīng)器的doeat方法監(jiān)聽(tīng)Person類對(duì)象eat(吃)這個(gè)動(dòng)作,將事件對(duì)象Event傳遞給doeat方法, * 事件對(duì)象封裝了事件源,new Event(this)中的this代表的就是事件源 */ listener.doeat(new Event(this)); } } /** * @Method: run * @Description: 設(shè)計(jì)Person的行為:跑 * @Anthor:孤傲蒼狼 * */ public void run() { if (listener != null) { /** * 調(diào)用監(jiān)聽(tīng)器的dorun方法監(jiān)聽(tīng)Person類對(duì)象run(跑)這個(gè)動(dòng)作,將事件對(duì)象Event傳遞給doeat方法, * 事件對(duì)象封裝了事件源,new Event(this)中的this代表的就是事件源 */ listener.dorun(new Event(this)); } } /** * @Method: registerListener * @Description: 這個(gè)方法是用來(lái)注冊(cè)對(duì)Person類對(duì)象的行為進(jìn)行監(jiān)聽(tīng)的監(jiān)聽(tīng)器 * @Anthor:孤傲蒼狼 * * @param listener */ public void registerListener(PersonListener listener) { this.listener = listener; } } /** * @ClassName: PersonListener(事件監(jiān)聽(tīng)器) * @Description: 設(shè)計(jì)Person類(事件源)的監(jiān)聽(tīng)器接口 * @author: 孤傲蒼狼 * @date: 2014-9-9 下午9:28:06 * */ interface PersonListener { /** * @Method: doeat * @Description: 這個(gè)方法是用來(lái)監(jiān)聽(tīng)Person對(duì)象eat(吃)這個(gè)行為動(dòng)作, * 當(dāng)實(shí)現(xiàn)類實(shí)現(xiàn)doeat方法時(shí)就可以監(jiān)聽(tīng)到Person類對(duì)象eat(吃)這個(gè)動(dòng)作 * @Anthor:孤傲蒼狼 * * @param e */ void doeat(Event e); /** * @Method: dorun * @Description: 這個(gè)方法是用來(lái)監(jiān)聽(tīng)Person對(duì)象run(跑)這個(gè)行為動(dòng)作, * 當(dāng)實(shí)現(xiàn)類實(shí)現(xiàn)dorun方法時(shí)就可以監(jiān)聽(tīng)到Person類對(duì)象run(跑)這個(gè)動(dòng)作 * @Anthor:孤傲蒼狼 * * @param e */ void dorun(Event e); } /** * @ClassName: Event(事件對(duì)象) * @Description:設(shè)計(jì)事件類,用來(lái)封裝事件源 * @author: 孤傲蒼狼 * @date: 2014-9-9 下午9:37:56 * */ class Event { /** * @Field: source * 事件源(Person就是事件源) */ private Person source; public Event() { } public Event(Person source) { this.source = source; } public Person getSource() { return source; } public void setSource(Person source) { this.source = source; } }
經(jīng)過(guò)這樣的設(shè)計(jì)之后,Peron類的對(duì)象就是可以被其他對(duì)象監(jiān)聽(tīng)了。測(cè)試代碼如下:
package me.gacl.observer; public class PersonTest { /** * @Method: main * @Description: 測(cè)試Person類 * @Anthor:孤傲蒼狼 * * @param args */ public static void main(String[] args) { // Person p = new Person(); //注冊(cè)監(jiān)聽(tīng)p對(duì)象行為的監(jiān)聽(tīng)器 p.registerListener(new PersonListener() { //監(jiān)聽(tīng)p吃東西這個(gè)行為 public void doeat(Event e) { Person p = e.getSource(); System.out.println(p + "在吃東西"); } //監(jiān)聽(tīng)p跑步這個(gè)行為 public void dorun(Event e) { Person p = e.getSource(); System.out.println(p + "在跑步"); } }); //p在吃東西 p.eat(); //p在跑步 p.run(); } }
運(yùn)行結(jié)果:
me.gacl.observer.Person@4a5ab2在吃東西
me.gacl.observer.Person@4a5ab2在跑步
二、JavaWeb中的監(jiān)聽(tīng)器
2.1、基本概念
JavaWeb中的監(jiān)聽(tīng)器是Servlet規(guī)范中定義的一種特殊類,它用于監(jiān)聽(tīng)web應(yīng)用程序中的ServletContext, HttpSession和 ServletRequest等域?qū)ο蟮膭?chuàng)建與銷毀事件,以及監(jiān)聽(tīng)這些域?qū)ο笾械膶傩园l(fā)生修改的事件。
2.2、Servlet監(jiān)聽(tīng)器的分類
在Servlet規(guī)范中定義了多種類型的監(jiān)聽(tīng)器,它們用于監(jiān)聽(tīng)的事件源分別為ServletContext,HttpSession和ServletRequest這三個(gè)域?qū)ο?
Servlet規(guī)范針對(duì)這三個(gè)對(duì)象上的操作,又把多種類型的監(jiān)聽(tīng)器劃分為三種類型:
•監(jiān)聽(tīng)域?qū)ο笞陨淼膭?chuàng)建和銷毀的事件監(jiān)聽(tīng)器。
•監(jiān)聽(tīng)域?qū)ο笾械膶傩缘脑黾雍蛣h除的事件監(jiān)聽(tīng)器。
•監(jiān)聽(tīng)綁定到HttpSession域中的某個(gè)對(duì)象的狀態(tài)的事件監(jiān)聽(tīng)器。
2.3、監(jiān)聽(tīng)ServletContext域?qū)ο蟮膭?chuàng)建和銷毀
ServletContextListener接口用于監(jiān)聽(tīng)ServletContext對(duì)象的創(chuàng)建和銷毀事件。實(shí)現(xiàn)了ServletContextListener接口的類都可以對(duì)ServletContext對(duì)象的創(chuàng)建和銷毀進(jìn)行監(jiān)聽(tīng)。
•當(dāng)ServletContext對(duì)象被創(chuàng)建時(shí),激發(fā)contextInitialized (ServletContextEvent sce)方法。
•當(dāng)ServletContext對(duì)象被銷毀時(shí),激發(fā)contextDestroyed(ServletContextEvent sce)方法。
•ServletContext域?qū)ο髣?chuàng)建和銷毀時(shí)機(jī):
創(chuàng)建:服務(wù)器啟動(dòng)針對(duì)每一個(gè)Web應(yīng)用創(chuàng)建ServletContext
銷毀:服務(wù)器關(guān)閉前先關(guān)閉代表每一個(gè)web應(yīng)用的ServletContext
范例:編寫(xiě)一個(gè)MyServletContextListener類,實(shí)現(xiàn)ServletContextListener接口,監(jiān)聽(tīng)ServletContext對(duì)象的創(chuàng)建和銷毀
1、編寫(xiě)監(jiān)聽(tīng)器,代碼如下:
package me.gacl.web.listener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; /** * @ClassName: MyServletContextListener * @Description: MyServletContextListener類實(shí)現(xiàn)了ServletContextListener接口, * 因此可以對(duì)ServletContext對(duì)象的創(chuàng)建和銷毀這兩個(gè)動(dòng)作進(jìn)行監(jiān)聽(tīng)。 * @author: 孤傲蒼狼 * @date: 2014-9-9 下午10:26:16 * */ public class MyServletContextListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { System.out.println("ServletContext對(duì)象創(chuàng)建"); } @Override public void contextDestroyed(ServletContextEvent sce) { System.out.println("ServletContext對(duì)象銷毀"); } }
2、在web.xml文件中注冊(cè)監(jiān)聽(tīng)器
我們?cè)谏厦娴闹兄v到,要想監(jiān)聽(tīng)事件源,那么必須將監(jiān)聽(tīng)器注冊(cè)到事件源上才能夠?qū)崿F(xiàn)對(duì)事件源的行為動(dòng)作進(jìn)行監(jiān)聽(tīng),在JavaWeb中,監(jiān)聽(tīng)的注冊(cè)是在web.xml文件中進(jìn)行配置的,如下:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <display-name></display-name> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <!-- 注冊(cè)針對(duì)ServletContext對(duì)象進(jìn)行監(jiān)聽(tīng)的監(jiān)聽(tīng)器 --> <listener> <description>ServletContextListener監(jiān)聽(tīng)器</description> <!--實(shí)現(xiàn)了ServletContextListener接口的監(jiān)聽(tīng)器類 --> <listener-class>me.gacl.web.listener.MyServletContextListener</listener-class> </listener> </web-app>
經(jīng)過(guò)這兩個(gè)步驟,我們就完成了監(jiān)聽(tīng)器的編寫(xiě)和注冊(cè),Web服務(wù)器在啟動(dòng)時(shí),就會(huì)自動(dòng)把在web.xml中配置的監(jiān)聽(tīng)器注冊(cè)到ServletContext對(duì)象上,這樣開(kāi)發(fā)好的MyServletContextListener監(jiān)聽(tīng)器就可以對(duì)ServletContext對(duì)象進(jìn)行監(jiān)聽(tīng)了。
2.4、監(jiān)聽(tīng)HttpSession域?qū)ο蟮膭?chuàng)建和銷毀
HttpSessionListener 接口用于監(jiān)聽(tīng)HttpSession對(duì)象的創(chuàng)建和銷毀
創(chuàng)建一個(gè)Session時(shí),激發(fā)sessionCreated (HttpSessionEvent se) 方法
銷毀一個(gè)Session時(shí),激發(fā)sessionDestroyed (HttpSessionEvent se) 方法。
范例:編寫(xiě)一個(gè)MyHttpSessionListener類,實(shí)現(xiàn)HttpSessionListener接口,監(jiān)聽(tīng)HttpSession對(duì)象的創(chuàng)建和銷毀
1、編寫(xiě)監(jiān)聽(tīng)器,代碼如下:
package me.gacl.web.listener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; /** * @ClassName: MyHttpSessionListener * @Description: MyHttpSessionListener類實(shí)現(xiàn)了HttpSessionListener接口, * 因此可以對(duì)HttpSession對(duì)象的創(chuàng)建和銷毀這兩個(gè)動(dòng)作進(jìn)行監(jiān)聽(tīng)。 * @author: 孤傲蒼狼 * @date: 2014-9-9 下午11:04:33 * */ public class MyHttpSessionListener implements HttpSessionListener { @Override public void sessionCreated(HttpSessionEvent se) { System.out.println( se.getSession() + "創(chuàng)建了?。?); } /* HttpSession的銷毀時(shí)機(jī)需要在web.xml中進(jìn)行配置,如下: * <session-config> <session-timeout>1</session-timeout> </session-config> 這樣配置就表示session在1分鐘之后就被銷毀 */ @Override public void sessionDestroyed(HttpSessionEvent se) { System.out.println("session銷毀了?。?); } }
2、在web.xml文件中注冊(cè)監(jiān)聽(tīng)器
<!--注冊(cè)針對(duì)HttpSession對(duì)象進(jìn)行監(jiān)聽(tīng)的監(jiān)聽(tīng)器--> <listener> <description>HttpSessionListener監(jiān)聽(tīng)器</description> <listener-class>me.gacl.web.listener.MyHttpSessionListener</listener-class> </listener> <!-- 配置HttpSession對(duì)象的銷毀時(shí)機(jī) --> <session-config> <!--配置HttpSession對(duì)象的1分鐘之后銷毀 --> <session-timeout>1</session-timeout> </session-config>
當(dāng)我們?cè)L問(wèn)jsp頁(yè)面時(shí),HttpSession對(duì)象就會(huì)創(chuàng)建,此時(shí)就可以在HttpSessionListener觀察到HttpSession對(duì)象的創(chuàng)建過(guò)程了,我們可以寫(xiě)一個(gè)jsp頁(yè)面觀察HttpSession對(duì)象創(chuàng)建的過(guò)程。
如下:index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" %> <!DOCTYPE HTML> <html> <head> <title>HttpSessionListener監(jiān)聽(tīng)器監(jiān)聽(tīng)HttpSession對(duì)象的創(chuàng)建</title> </head> <body> 一訪問(wèn)JSP頁(yè)面,HttpSession就創(chuàng)建了,創(chuàng)建好的Session的Id是:${pageContext.session.id} </body> </html>
運(yùn)行結(jié)果如下:
2.5、監(jiān)聽(tīng)ServletRequest域?qū)ο蟮膭?chuàng)建和銷毀
ServletRequestListener接口用于監(jiān)聽(tīng)ServletRequest 對(duì)象的創(chuàng)建和銷毀
Request對(duì)象被創(chuàng)建時(shí),監(jiān)聽(tīng)器的requestInitialized(ServletRequestEvent sre)方法將會(huì)被調(diào)用
Request對(duì)象被銷毀時(shí),監(jiān)聽(tīng)器的requestDestroyed(ServletRequestEvent sre)方法將會(huì)被調(diào)用
ServletRequest域?qū)ο髣?chuàng)建和銷毀時(shí)機(jī):
創(chuàng)建:用戶每一次訪問(wèn)都會(huì)創(chuàng)建request對(duì)象
銷毀:當(dāng)前訪問(wèn)結(jié)束,request對(duì)象就會(huì)銷毀
范例:編寫(xiě)一個(gè)MyServletRequestListener類,實(shí)現(xiàn)ServletRequestListener接口,監(jiān)聽(tīng)ServletRequest對(duì)象的創(chuàng)建和銷毀
1、編寫(xiě)監(jiān)聽(tīng)器,代碼如下:
package me.gacl.web.listener; import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestListener; /** * @ClassName: MyServletRequestListener * @Description: MyServletRequestListener類實(shí)現(xiàn)了ServletRequestListener接口, * 因此可以對(duì)ServletRequest對(duì)象的創(chuàng)建和銷毀這兩個(gè)動(dòng)作進(jìn)行監(jiān)聽(tīng)。 * @author: 孤傲蒼狼 * @date: 2014-9-9 下午11:50:08 * */ public class MyServletRequestListener implements ServletRequestListener { @Override public void requestDestroyed(ServletRequestEvent sre) { System.out.println(sre.getServletRequest() + "銷毀了??!"); } @Override public void requestInitialized(ServletRequestEvent sre) { System.out.println(sre.getServletRequest() + "創(chuàng)建了??!"); } }
2、在web.xml文件中注冊(cè)監(jiān)聽(tīng)器
<!--注冊(cè)針對(duì)ServletRequest對(duì)象進(jìn)行監(jiān)聽(tīng)的監(jiān)聽(tīng)器--> <listener> <description>ServletRequestListener監(jiān)聽(tīng)器</description> <listener-class>me.gacl.web.listener.MyServletRequestListener</listener-class> </listener>
測(cè)試結(jié)果如下:
從運(yùn)行結(jié)果中可以看到,用戶每一次訪問(wèn)都會(huì)創(chuàng)建request對(duì)象,當(dāng)訪問(wèn)結(jié)束后,request對(duì)象就會(huì)銷毀。
以上就是對(duì)監(jiān)聽(tīng)器的一些簡(jiǎn)單講解。
相關(guān)文章
springboot接收http請(qǐng)求,解決參數(shù)中+號(hào)變成空格的問(wèn)題
這篇文章主要介紹了springboot接收http請(qǐng)求,解決參數(shù)中+號(hào)變成空格的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08Java SSM實(shí)現(xiàn)前后端協(xié)議聯(lián)調(diào)詳解上篇
首先我們已經(jīng)知道,在現(xiàn)在流行的“前后端完全分離”架構(gòu)中,前后端聯(lián)調(diào)是一個(gè)不可能避免的問(wèn)題,這篇文章主要介紹了Java SSM實(shí)現(xiàn)前后端協(xié)議聯(lián)調(diào)過(guò)程2022-08-08Spring導(dǎo)入properties配置文件代碼示例
這篇文章主要介紹了Spring導(dǎo)入properties配置文件代碼示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10Java Spring-Cache key配置注意事項(xiàng)介紹
本文主要對(duì)java spring-cache key配置注意事項(xiàng)進(jìn)行了介紹,小編覺(jué)得還是挺不錯(cuò)的,這里分享給大家,供需要的朋友參考。2017-10-10Java中多個(gè)線程交替循環(huán)執(zhí)行的實(shí)現(xiàn)
有些時(shí)候面試官經(jīng)常會(huì)問(wèn),兩個(gè)線程怎么交替執(zhí)行呀,本文就來(lái)詳細(xì)的介紹一下Java中多個(gè)線程交替循環(huán)執(zhí)行的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-01-01解決SpringBoot返回結(jié)果如果為null或空值不顯示處理問(wèn)題
這篇文章主要介紹了解決SpringBoot返回結(jié)果如果為null或空值不顯示處理問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07idea自帶database連接mysql失敗問(wèn)題的解決辦法
在IDEA?帶的數(shù)據(jù)庫(kù)連接?具中,可以連接MySQL數(shù)據(jù)庫(kù),但是有的時(shí)候連接出現(xiàn)錯(cuò)誤,連接不上數(shù)據(jù)庫(kù),下面這篇文章主要給大家介紹了關(guān)于idea自帶database連接mysql失敗問(wèn)題的解決辦法,需要的朋友可以參考下2023-06-06