一、监听器介绍
1.1、监听器的概念
监听器是一个专门用于对其他对象身上发生的事件或状态改变进行监听和相应处理的对象,当被监视的对象发生情况时,立即采取相应的行动。监听器其实就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法立即被执行。
1.2、监听器案例——监听window窗口的事件监听器
package com.listener.demo; import java.awt.Frame; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; public class Demo1 { /** * java的事件监听机制 * 1、事件监听涉及到三个组件:事件源、事件对象、事件监听器 * 2、当事件源上发生某一个动作时,它会调用事件监听器的一个方法,并在调用该方法时把事件对象传递进去, * 开发人员在监听器中通过事件对象,就可以拿到事件源,从而对事件源进行操作。 */ public static void main(String[] args) { Frame f = new Frame(); f.setSize(400, 400); f.setVisible(true); //注册事件监听器 f.addWindowListener(new WindowListener(){ public void windowActivated(WindowEvent e) { } public void windowClosed(WindowEvent e) { } /** * 当window窗体关闭时就会WindowListener这个监听器监听到, * 监听器就会调用windowClosing方法处理window窗体关闭时的动作 */ public void windowClosing(WindowEvent e) { //通过事件对象e来获取事件源对象 Frame f = (Frame) e.getSource(); System.out.println(f+"窗体正在关闭"); f.dispose(); } public void windowDeactivated(WindowEvent e) { } public void windowDeiconified(WindowEvent e) { } public void windowIconified(WindowEvent e) { } public void windowOpened(WindowEvent e) { } }); } }
1.3、设计一个可以被别的对象监听的对象
我们平时做开发的时候,我们是写监听器去监听其他对象,那么我们如果想设计一个对象,让这个对象可以被别的对象监听又该怎么做呢,可以按照严格的事件处理模型来设计一个对象,这个对象就可以被别的对象监听,事件处理模型涉及到三个组件:事件源、事件对象、事件监听器。
下面我们来按照事件处理模型来设计一个Person对象,具体代码如下:
package com.observer; /** * @ClassName: Person(事件源) * @Description: 设计一个Person类作为事件源,这个类的对象的行为(比如吃饭、跑步)可以被其他的对象监听 * @author: hdb * @date: 2017-11-9 20:26:06 * */ public class Person { /** * @Field: listener * 在Person类中定义一个PersonListener变量来记住传递进来的监听器 */ private PersonListener listener; /** * @Method: eat * @Description: 设计Person的行为:吃 * @Anthor:hdb * */ public void eat() { if (listener != null) { /** * 调用监听器的doeat方法监听Person类对象eat(吃)这个动作,将事件对象Event传递给doeat方法, * 事件对象封装了事件源,new Event(this)中的this代表的就是事件源 */ listener.doeat(new Event(this)); } } /** * @Method: run * @Description: 设计Person的行为:跑 * @Anthor:hdb * */ public void run() { if (listener != null) { /** * 调用监听器的dorun方法监听Person类对象run(跑)这个动作,将事件对象Event传递给doeat方法, * 事件对象封装了事件源,new Event(this)中的this代表的就是事件源 */ listener.dorun(new Event(this)); } } /** * @Method: registerListener * @Description: 这个方法是用来注册对Person类对象的行为进行监听的监听器 * @Anthor:hdb * * @param listener */ public void registerListener(PersonListener listener) { this.listener = listener; } } /** * @ClassName: PersonListener(事件监听器) * @Description: 设计Person类(事件源)的监听器接口 * @author: hdb * @date: 2017-11-9 下午9:28:06 * */ interface PersonListener { /** * @Method: doeat * @Description: 这个方法是用来监听Person对象eat(吃)这个行为动作, * 当实现类实现doeat方法时就可以监听到Person类对象eat(吃)这个动作 * @Anthor:hdb * * @param e */ void doeat(Event e); /** * @Method: dorun * @Description: 这个方法是用来监听Person对象run(跑)这个行为动作, * 当实现类实现dorun方法时就可以监听到Person类对象run(跑)这个动作 * @Anthor:hdb * * @param e */ void dorun(Event e); } /** * @ClassName: Event(事件对象) * @Description:设计事件类,用来封装事件源 * @author: hdb * @date: 2017-11-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; } }
经过这样的设计之后,Peron类的对象就是可以被其他对象监听了。测试代码如下:
package com.observer; public class PersonTest { /** * @Method: main * @Description: 测试Person类 * @Anthor:hdb * * @param args */ public static void main(String[] args) { // Person p = new Person(); //注册监听p对象行为的监听器 p.registerListener(new PersonListener() { //监听p吃东西这个行为 public void doeat(Event e) { Person p = e.getSource(); System.out.println(p + "在吃东西"); } //监听p跑步这个行为 public void dorun(Event e) { Person p = e.getSource(); System.out.println(p + "在跑步"); } }); //p在吃东西 p.eat(); //p在跑步 p.run(); } }
运行结果:
com.observer.Person@4a5ab2在吃东西
com.observer.Person@4a5ab2在跑步
二、JavaWeb中的监听器
2.1、基本概念
概念:
JavaWeb中的监听器是Servlet规范中定义的一种特殊类,它用于监听web应用程序中的ServletContext, HttpSession和 ServletRequest等域对象的创建与销毁事件,以及监听这些域对象中的属性发生修改的事件。当范围对象的状态发生变化的时候,服务器自动调用监听器对象中的方法。
用途:
统计在线人数和在线用户,利用HttpSessionLisener
系统加载时进行信息初始化:利用ServletContextListener
统计网站访问量
实现访问监控
2.2、Servlet监听器的分类
在Servlet规范中定义了多种类型的监听器,它们用于监听的事件源分别为ServletContext,HttpSession和ServletRequest这三个域对象
Servlet规范针对这三个对象上的操作,又把多种类型的监听器划分为三种类型:
- 监听域对象自身的创建和销毁的事件监听器。
- 监听域对象属性的增加和删除的事件监听器。
- 监听绑定到HttpSession域中某个对象的状态的事件监听器。
2.3、监听ServletContext域对象的创建和销毁
ServletContextListener接口用于监听ServletContext对象的创建和销毁事件。实现了ServletContextListener接口的类都可以对ServletContext对象的创建和销毁进行监听。
当ServletContext对象被创建时,激发contextInitialized (ServletContextEvent sce)方法。
当ServletContext对象被销毁时,激发contextDestroyed(ServletContextEvent sce)方法。
ServletContext域对象创建和销毁时机:
创建:服务器启动针对每一个Web应用创建ServletContext
销毁:服务器关闭前先关闭代表每一个web应用的ServletContext
范例:编写一个MyServletContextListener类,实现ServletContextListener接口,监听ServletContext对象的创建和销毁
1、编写监听器,代码如下:
package com.web.listener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; /** * @ClassName: MyServletContextListener * @Description: MyServletContextListener类实现了ServletContextListener接口, * 因此可以对ServletContext对象的创建和销毁这两个动作进行监听。 * @author: hdb * @date: 2017-11-9 下午10:26:16 * */ public class MyServletContextListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { System.out.println("ServletContext对象创建"); } @Override public void contextDestroyed(ServletContextEvent sce) { System.out.println("ServletContext对象销毁"); } }
2、在web.xml文件中注册监听器
我们在上面的中讲到,要想监听事件源,那么必须将监听器注册到事件源上才能够实现对事件源的行为动作进行监听,在JavaWeb中,监听的注册是在web.xml文件中进行配置的,如下:
<?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> <!-- 注册针对ServletContext对象进行监听的监听器 --> <listener> <description>ServletContextListener监听器</description> <!--实现了ServletContextListener接口的监听器类 --> <listener-class>com.web.listener.MyServletContextListener</listener-class> </listener> </web-app>
经过这两个步骤,我们就完成了监听器的编写和注册,Web服务器在启动时,就会自动把在web.xml中配置的监听器注册到ServletContext对象上,这样开发好的MyServletContextListener监听器就可以对ServletContext对象进行监听了。
在Servlet3.0中,监听器的配置可以直接在代码中通过注释来完成,无需在web.xml中再配置。@WebListener //在此注明以下类是监听器
2.4、监听HttpSession域对象的创建和销毁
HttpSessionListener 接口用于监听HttpSession对象的创建和销毁
创建一个Session时,激发sessionCreated (HttpSessionEvent se) 方法
销毁一个Session时,激发sessionDestroyed (HttpSessionEvent se) 方法。
范例:编写一个MyHttpSessionListener类,实现HttpSessionListener接口,监听HttpSession对象的创建和销毁
1、编写监听器,代码如下:
package com.web.listener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; /** * @ClassName: MyHttpSessionListener * @Description: MyHttpSessionListener类实现了HttpSessionListener接口, * 因此可以对HttpSession对象的创建和销毁这两个动作进行监听。 * @author: hdb * @date: 2017-11-9 下午11:04:33 * */ public class MyHttpSessionListener implements HttpSessionListener { @Override public void sessionCreated(HttpSessionEvent se) { System.out.println( se.getSession() + "创建了!!"); } /* HttpSession的销毁时机需要在web.xml中进行配置,如下: * <session-config> <session-timeout>1</session-timeout> </session-config> 这样配置就表示session在1分钟之后就被销毁 */ @Override public void sessionDestroyed(HttpSessionEvent se) { System.out.println("session销毁了!!"); } }
2、在web.xml文件中注册监听器
<!--注册针对HttpSession对象进行监听的监听器--> <listener> <description>HttpSessionListener监听器</description> <listener-class>com.web.listener.MyHttpSessionListener</listener-class> </listener> <!-- 配置HttpSession对象的销毁时机 --> <session-config> <!--配置HttpSession对象的1分钟之后销毁 --> <session-timeout>1</session-timeout> </session-config>
当我们访问jsp页面时,HttpSession对象就会创建,此时就可以在HttpSessionListener观察到HttpSession对象的创建过程了,我们可以写一个jsp页面观察HttpSession对象创建的过程。
如下:index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" %> <!DOCTYPE HTML> <html> <head> <title>HttpSessionListener监听器监听HttpSession对象的创建</title> </head> <body> 一访问JSP页面,HttpSession就创建了,创建好的Session的Id是:${pageContext.session.id} </body> </html>
运行结果如下:
2.5、监听ServletRequest域对象的创建和销毁
ServletRequestListener接口用于监听ServletRequest 对象的创建和销毁
Request对象被创建时,监听器的requestInitialized(ServletRequestEvent sre)方法将会被调用
Request对象被销毁时,监听器的requestDestroyed(ServletRequestEvent sre)方法将会被调用
ServletRequest域对象创建和销毁时机:
创建:用户每一次访问都会创建request对象
销毁:当前访问结束,request对象就会销毁
范例:编写一个MyServletRequestListener类,实现ServletRequestListener接口,监听ServletRequest对象的创建和销毁
1、编写监听器,代码如下:
package com.web.listener; import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestListener; /** * @ClassName: MyServletRequestListener * @Description: MyServletRequestListener类实现了ServletRequestListener接口, * 因此可以对ServletRequest对象的创建和销毁这两个动作进行监听。 * @author: hdb * @date: 2017-11-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() + "创建了!!"); } }
2、在web.xml文件中注册监听器
<!--注册针对ServletRequest对象进行监听的监听器-->
<listener>
<description>ServletRequestListener监听器</description>
<listener-class>com.web.listener.MyServletRequestListener</listener-class>
</listener>
测试结果如下:
从运行结果中可以看到,用户每一次访问都会创建request对象,当访问结束后,request对象就会销毁。
2.6、getAttribute与getParameter的区别
这部分是对JSP的扩展,经常在JSP或者Servlet中获取数据,那么getAttribute与getParameter有什么区别呢?
1 从获取到数据的来源来说:
getAttribtue获取到的是web容器中的值,比如:
我们在Servlet中通过setAttribute设定某个值,这个值存在于容器中,就可以通过getAttribute方法获取;
getParameter获取到的是通过http传来的值,比如这样一个http请求:
http:localhost:8080/test/test.html?username=xingoo
还有其他的GET和POST方式,都可以通过getParameter来获取。
2 从获取到的数据类型来说:
getAttribute返回的是一个对象,Object。
getParameter返回的是,前面页面中某个表单或者http后面参数传递的值,是个字符串。
2.7、常用监听器
除了上面监听session建立与销毁的listener外,还有以下几个常用的监听器。
1:监听session属性的增加、移除以及属性值改变的HttpSessionAttributeListener
2:监听web上下文的初始化(服务器已准备好接收请求)与销毁的ServletContextListener
3:监听web上下文属性的增加、删除、属性值变化的ServletContextAttributeListener
4:监听request的创建与销毁的ServletRequestListener
5:监听request的属性的增加、删除、属性值变化的ServletRequestAttributeListener