一、什么是监听器
监听器是一个实现了特定接口的普通Java类,用于监听其他对象的创建和销毁,监听其他对象的方法执行和属性改变,被监听的对象如果发生了上述的事件,监听器的某个方法就会立刻执行。
作用:
监听其他对象所发生的变化,主要用于图形化界面的程序
三个要素:
事件源:被监听的对象
监听器:用来监听事件源,简单理解为事件的处理程序。
事件:也就是发生的那件事,当事件发生的时候,我们的监听程序应该被执行
三个步骤:
1、要有事件源
2、创建一个监听器(写事件的处理程序)
3、把事件和监听器绑定到一起
二、监听器的入门案例
我们来创建一个窗口,为窗口绑定监听器,实现关闭按钮的关闭功能。
创建一个窗口
public class MyFrame {
public static void main(String[] args) {
//创建窗口对象
Frame f = new Frame();
//设置窗口可见
f.setVisible(true);
//设置窗口的宽和高
f.setSize(500, 500);
//为窗口绑定监听器
f.addWindowListener(new MyWindowListener());
}
创建一个监听器
上面为窗口绑定监听器调用的addWindowListener方法需要传入一个WindowListener接口的实现类,如果我们直接创建一个监听器来实现这个接口的话,必须实现这个接口的所有方法,否则系统就会报错。所以我们可以创建一个类来继承这个接口,在这个类中对所有的方法进行空实现,然后监听器继承这个类,只需要重写我们需要的方法就可以了。这个类也叫做适配器,Java已经给我们准备好了,这个类就是WindowAdapter。
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
public class MyWindowListener extends WindowAdapter{
@Override
public void windowClosing(WindowEvent e) {
//关闭窗口
e.getWindow().dispose();
}
}
案例的改进
由于我们的监听器使用比较少,一般只需要使用一次,就像我们的关闭按钮,只需要在关闭窗口的时候使用一次,所以我们可以通过创建内部类或者匿名内部类的方法来创建监听器。
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class MyFrame {
public static void main(String[] args) {
//创建窗口对象
Frame f = new Frame();
//设置窗口可见
f.setVisible(true);
//设置窗口的宽和高
f.setSize(500, 500);
//为窗口绑定监听器
//f.addWindowListener(new MyWindowListener());
f.addWindowListener(new WindowAdapter() {
//匿名内部类
@Override
public void windowClosing(WindowEvent e) {
e.getWindow().dispose();
}
});
}
//内部类
static class MyInnerWindowListener extends WindowAdapter{
@Override
public void windowClosing(WindowEvent e) {
e.getWindow().dispose();
}
}
}
三、自定义监听器
我们来创建一个监听器,实现对其他类的监听。
创建监听器接口
创建一个监听器接口,这个监听器接口实现两个功能,在事件源的eat和sleep方法执行前执行,分别是preEat()和preSleep()。
public interface StudentListener {
public void preEat();
public void preSleep();
}
创建事件源
创建一个Student类,类中有三个方法eat()、sleep()和addStudentListener(),并为eat和sleep方法设置监听。
public class Student {
private StudentListener listener;
public void eat() {
//对事件进行监听,事件发生了,监听器就回执行一些功能
if (listener != null) {
listener.preEat();
}
System.out.println("吃饭");
}
public void sleep() {
if (listener != null) {
listener.preSleep();
}
System.out.println("睡觉");
}
public void addStudentListener(StudentListener listener) {
this.listener = listener;
}
}
创建测试类,绑定监听器
public class StudentTest {
public static void main(String[] args) {
Student s = new Student();
//绑定监听器
s.addStudentListener(new StudentListener() {
@Override
public void preSleep() {
System.out.println("睡觉之前先洗澡");
}
@Override
public void preEat() {
System.out.println("吃饭之前先洗手");
}
});
//执行方法
s.eat();
s.sleep();
}
}
执行结果
四、Servlet中的监听器
1、分类
Servlet为我们提供了8个监听器,可以分为三种。
- 监听域对象的创建和销毁 3种
ServletContext
HttpSessionListener
ServletRequestListener - 监听3个域对象存数据,取数据,删除数据的变化 3种
ServletContextAttributeListener
HttpSessionAttributeListener
ServletRequestAttributeListener
上面两种监听器的编写步骤
(1)创建一个普通的Java类
(2)让该类实现监听器的接口
(3)在该类中实现监听器接口的所有方法
(4)在web.xml文件中通过<listener>标签来配置监听器
- 监听JavaBean自己的状态 2种
HttpSessionBindingListener:帮助JavaBean对象感知自己在session对象中的绑定和解绑,也就是感知JavaBean对象被添加到session对象中和被删除两种状态
HttpSessionActivationListener:帮助JavaBean对象感知自己在session对象中被钝化或者恢复
这两个特殊的监听器不需要再web.xml文件中配置,让JavaBean实现这个接口就可以了
2、监听域对象的创建和销毁
由于三种域对象的创建和销毁比较相似,所以我们就介绍ServletContext和HttpSession。我们可以直接通过Eclipse创建监听器。
(1)ServletContext域对象的创建与销毁
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class MyServletContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent arg0) {
//监听ServletContext域对象的创建
System.out.println("ServletContext对象被创建了");
}
public void contextDestroyed(ServletContextEvent arg0) {
//监听ServletContext域对象的销毁
System.out.println("ServletContext对象被销毁了");
}
}
ServletContext域对象在服务器启动的时候创建
ServletContext域对象在服务器正常关闭的时候销毁
ServerContext域对象的销毁
(2)HttpSession域对象的创建与销毁
创建MyHttpSessionListener
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class MyHttpSessionListener implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent arg0) {
//监听Session域对象的创建
System.out.println("Session对象被创建了");
}
public void sessionDestroyed(HttpSessionEvent arg0) {
//监听Session域对象的销毁
System.out.println("Session对象被销毁了");
}
}
创建Session对象注销页面
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LogoutServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
session.invalidate();
System.out.println("Session对象被销毁了");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
创建测试页面
session属性默认为true,也就是打开页面的时候自动创建session对象
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" session="true"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>hello listener</h1>
<a href="${pageContext.request.contextPath}/LogoutServlet">注销</a>
</body>
</html>
打开浏览器运行demo1.jsp,创建session对象
控制台
点击注销,销毁session对象
销毁session对象
(3)三个域对象的生命周期
ServletContext生命周期:应用加载或者服务器启动的时候创建,服务器关闭的时候销毁
HTTPSession生命周期:会话开始的时候创建,超过30分钟,非正常关闭或者调用invalidate方法销毁
ServletRequest生命周期:一次请求开始的时候创建,响应结束之后就被销毁
(4)三个域对象监听器的作用
根据三个域对象的生命周期不同,他们的监听器应用也不同
对于ServletContextListener来说,他可以做一些应用级别的数据保存或者定时发送东西,例如:企业给用户发的生日邮件,这就是一个定时任务,可以通过ServletContextListener进行配置执行;还可以进行运营数据的备份。
对于HttpSessionListener来说,可以用在购物车中,在session对象被销毁前,把购物车中的数据保存到数据库中。
对于ServletRequestListener来说,他的创建太频繁,基本没有用。
3、监听域对象中属性变化
三个域对象属性变化的监听非常相似,这里使用HttpSessionAttributeListener进行说明,其他的域对象请读者自行测试。
创建Session域对象的监听器
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
public class MyHttpSessionAttributeListener implements HttpSessionAttributeListener {
public void attributeRemoved(HttpSessionBindingEvent arg0) {
//监听HttpSession属性的删除
System.out.println("Session域对象中的属性的值被删除了");
}
public void attributeAdded(HttpSessionBindingEvent arg0) {
//监听HttpSession属性的创建
System.out.println("Session域对象中添加了新的属性");
}
public void attributeReplaced(HttpSessionBindingEvent arg0) {
//监听HttpSession属性的替换
System.out.println("Session域对象中的属性的值被替换了");
}
}
创建Servlet修改Session域对象的属性
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class DemoServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取session对象
HttpSession session = request.getSession();
//添加属性
session.setAttribute("username", "zhangsan");
session.setAttribute("password", "123456");
//替换属性
session.setAttribute("username", "lisi");
//删除属性
session.removeAttribute("password");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
Session域对象属性的修改
4、JavaBean的感知监听器
JavaBean的感知监听器能够帮助JavaBean对象感知自己在session域对象中的状态,是一个特殊的监听器,不需要再web.xml文件中进行配置,只需要让JavaBean对象继承两个接口就可以了
首先创建一个JavaBean,继承Serializable接口
import java.io.Serializable;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
public class User implements Serializable{
private String username;
private String password;
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(String username, String password) {
super();
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
(1)JavaBean对象对绑定和解绑的感知
绑定是指将JavaBean对象存放在session域对象中,解绑就是将JavaBean对象从session域对象中删除。需要JavaBean继承HttpSessionBindingListener接口,并重写其中的两个方法。
import java.io.Serializable;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
public class User implements Serializable,HttpSessionBindingListener {
private String username;
private String password;
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(String username, String password) {
super();
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public void valueBound(HttpSessionBindingEvent arg0) {
//监听JavaBean对象的绑定
System.out.println("JavaBean对象被绑定了");
}
@Override
public void valueUnbound(HttpSessionBindingEvent arg0) {
//监听JavaBean对象的解绑
System.out.println("JavaBean对象被解绑了");
}
}
**创建UserTestServlet进行测试
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.itheima.domain.User;
public class UserTestServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取session对象
HttpSession session = request.getSession();
//创建JavaBean对象
User user = new User("zhangsan","123456");
//绑定JavaBean对象
session.setAttribute("User", user);
//解绑JavaBean对象
session.removeAttribute("User");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
打开浏览器运行UserTestServlet,控制台运行结果如下
(2)JavaBean对象对钝化和恢复的感知
我们在介绍session域对象的时候,说过当session对象正常存活的时候,如果tomcat正常关闭,那么session对象会被钝化,数据会保存到tomcat的work目录下,再次打开tomcat的时候就可以恢复这些数据,JavaBean对象可以对session对象的钝化和恢复进行感知,需要实现HttpSessionActivationListener接口。
import java.io.Serializable;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import javax.servlet.http.HttpSessionEvent;
public class User implements Serializable,HttpSessionBindingListener,HttpSessionActivationListener {
private String username;
private String password;
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(String username, String password) {
super();
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public void valueBound(HttpSessionBindingEvent arg0) {
//监听JavaBean对象的绑定
System.out.println("JavaBean对象被绑定了");
}
@Override
public void valueUnbound(HttpSessionBindingEvent arg0) {
//监听JavaBean对象的解绑
System.out.println("JavaBean对象被解绑了");
}
@Override
public void sessionDidActivate(HttpSessionEvent arg0) {
//session对象被恢复时调用
System.out.println("session对象被恢复了");
}
@Override
public void sessionWillPassivate(HttpSessionEvent arg0) {
//session对象被钝化时调用
System.out.println("session对象被钝化了");
}
}
将UserTestServlet中session对象的解绑注释掉,打开浏览器,访问UserTestServlet
正常关闭tomcat,控制台输出结果如下
钝化
再次打开tomcat,控制台输出结果如下
恢复
网友评论