首页 > 代码库 > 监听器
监听器
1 事件三要素
a)事件源:操作事件的对象,例如:窗体Frame
b)事件监听器:事件监听器监听事件源,例如WindowListner,它是一个接口
c)事件,例如:单击事件,通过事件,可以取得事件源
2 适配器模式
a)当一个接口有较多的方法时,而实现类只需对其中少数几个实现,此时可以使用适配器模式
b)适配器模式常用于GUI编程,而web监听器中并不存在Adapter(适配器)
*3 八种web监听器详解
a)Web中有三个事件源,分别是ServletContext->HttpSession->ServletRequest
***注意:Listener都是单例模式,当web应用启动时创建Listener实例,并在web应用停止时销毁Listener实例。
b)ServletContext对象
>>创建和销毁:ServletContextListener.
Web容器部署时容器自动调用contextInitialized()方法,
Web容器重新部署时容器自动调用contextDestroyed()方法。
>>属性变化:ServletContextAttributeListner
application.setAttirbute("name","jack") ----> void attributeAdded(ServletContextAttributeEvent event)
setAttribute("name","杰克") ----> void attributeReplaced(ServletContextAttributeEvent event)
removeAttribute("name") ----> void attributeRemoved(ServletContextAttributeEvent event)
案例:
1)利用监听器初始化数据库
code: public class MyServletContextListener implements ServletContextListener { private ContextDao dao = new ContextDao(); @Override public void contextInitialized(ServletContextEvent event) { try { dao.createTable(); System.out.println("创建表成功!"); dao.insertTable("jack"); System.out.println("插入数据成功!"); } catch (SQLException e) { e.printStackTrace(); } } @Override public void contextDestroyed(ServletContextEvent event) { try { dao.dropTable(); System.out.println("删除表成功!"); } catch (SQLException e) { e.printStackTrace(); } } } web.xml <listener> <listener-class>listener.context.MyServletContextListener</listener-class> </listener>
2) 指定时间往数据库插入一次数据,5秒的延迟
public class MyServletContextListener1 implements ServletContextListener { private TimerDao dao = new TimerDao(); private Timer timer; private TimerTask task; public MyServletContextListener1() { this.timer = new Timer(); /*初始化TimerTask对象*/ task = new TimerTask() { @Override public void run() { try { dao.insertTable(UUID.randomUUID().toString(), new Date()); } catch (SQLException e) { e.printStackTrace(); } } }; } public void contextInitialized(ServletContextEvent event) { try { dao.createTable(); //每隔5秒像数据库插入一条数据 timer.schedule(task, 0, 1000*5); } catch (SQLException e) { e.printStackTrace(); } } public void contextDestroyed(ServletContextEvent event) { try { dao.destoryTable(); } catch (SQLException e) { e.printStackTrace(); } } }
3)ServletContextAttributeListener测试
code:
//listenerpublic class MyServletContextAttributeListener implements ServletContextAttributeListener {@Overridepublic void attributeAdded(ServletContextAttributeEvent event) {System.out.println("attributeAdded==>" + event.getName() + " : " + event.getValue());}@Overridepublic void attributeReplaced(ServletContextAttributeEvent event) {//注意:此时的getValue得到的是替换前的value值。System.out.println("attributeReplaced==>" + event.getName() + " : " + event.getValue());}@Overridepublic void attributeRemoved(ServletContextAttributeEvent event) {System.out.println("attriattributeRemoved==>" + event.getName() + " : " + event.getValue());}}//javaapplication.setAttribute("name", "jack");application.setAttribute("name", "杰克");application.removeAttribute("name");//输出结果:attributeAdded==>name : jackattributeReplaced==>name : jackattriattributeRemoved==>name : 杰克 c)ServletRequest对象>>创建和销毁:ServletRequestListener.每次请求容器自动调用requestInitialized()方法,响应完毕容器自动调用requestDestroyed()方法>>属性变化:ServletRequestAttributeListner(与ServletContextAttributeListener类似,例子省略)request.setAttirbute("name","jack")setAttribute("name","杰克")removeAttribute("name")
案例:
1)回写显示访问此网站的次数,访问者ip,以及访问者本地时间【js】。
code:public class MyServletRequestListener implements ServletRequestListener {private Integer queryNum = 0;@Overridepublic void requestDestroyed(ServletRequestEvent event) {System.out.println("requestDestroyed()");}@Overridepublic void requestInitialized(ServletRequestEvent event) {HttpServletRequest request = (HttpServletRequest) event.getServletRequest();String ip = request.getRemoteAddr();synchronized (this) {queryNum++;}request.setAttribute("ip", ip);request.setAttribute("num", queryNum);System.out.println("requestInitialized()");}}js:<script type="text/javascript">function nowTime() {window.setInterval("updateTime()", 1000);}function updateTime() {var nowDate = new Date().toLocaleString();//定位区域并输出var spanElement = document.getElementById("spanId");spanElement.innerHTML = nowDate;}</script></head><body onl oad="nowTime()">您的ip:${requestScope.ip} <br/>网站访问次数:${requestScope.num} <br/>当前时间:<span id="spanId"></span> <br/></body>
d)HttpSession对象
>>创建和销毁:HttpSessionListener.
当Web容器创建HttpSession对象时容器自动调用sessionCreated()方法
当Web容器销毁HttpSession对象时容器自动调用sessionDestroyed()方法
>>属性变化:HttpSessionAttributeListner (与ServletContextAttributeListener类似,例子省略)
session.setAttirbute("name","jack")
setAttribute("name","杰克")
removeAttribute("name")
案例:
1)HttpSessionListener调用函数测试
web.xml<listener><listener-class>listener.session.MyHttpSessionListener</listener-class></listener><!-- 设置session的过期时间为1分钟,默认为30分钟 【注意:实际上时间并不为1分钟】--><session-config><session-timeout>1</session-timeout></session-config>code:public class MyHttpSessionListener implements HttpSessionListener {@Overridepublic void sessionCreated(HttpSessionEvent event) {HttpSession session = event.getSession();//若为新创建的sessionif (session.isNew()) {System.out.println("sessionCreated, ID:" + session.getId());}}@Overridepublic void sessionDestroyed(HttpSessionEvent event) {HttpSession session = event.getSession();if (!session.isNew()) {System.out.println("sessionDestroyed, ID:" + session.getId());}}}
2)利用Session扫描器:精确控制session的声明周期
code:
public class SessionScanner implements HttpSessionListener, ServletContextListener {private List<HttpSession> sessionList = Collections.synchronizedList(new ArrayList<HttpSession>());Timer timer = new Timer();@Overridepublic void contextInitialized(ServletContextEvent event) {timer.schedule(new MyTimerTask(sessionList), 0, 1*1000);}@Overridepublic void contextDestroyed(ServletContextEvent event) {//取消当前定时器timer.cancel();}@Overridepublic void sessionCreated(HttpSessionEvent event) {HttpSession session = event.getSession();synchronized (sessionList) {sessionList.add(session);}System.out.println("Session产生:" + session.hashCode() + " : " + new Date().toLocaleString() );}@Overridepublic void sessionDestroyed(HttpSessionEvent event) {HttpSession session = event.getSession();System.out.println("Session销毁:" + session.hashCode() + " : " + new Date().toLocaleString());}}class MyTimerTask extends TimerTask {public MyTimerTask(List<HttpSession> sessionList) {this.list = sessionList;}@Overridepublic void run() {synchronized (list) { ListIterator<HttpSession> listIt = list.listIterator(); while(listIt.hasNext()) { HttpSession session = listIt.next(); //测试HttpSession的存在时间 int middle = (int) ( System.currentTimeMillis() - session.getLastAccessedTime() ) / 1000;if (middle > 60 ) {//从list中移除当前HttpSession元素listIt.remove();//使得此session失效session.invalidate();}}}}}
e)HttpSessionBindListener监听器,专用于监听JavaBean对象在HttpSession中的状态情况:
检测JavaBean在Session中的状态,感知自己何时绑定在HttpSession中,何时从HttpSession中移除。
code:
//listenerpublic class User implements HttpSessionBindingListener {@Overridepublic void valueBound(HttpSessionBindingEvent event) {System.out.println("valueBound==>" + event.getName() + " : " + event.getValue());}@Overridepublic void valueUnbound(HttpSessionBindingEvent event) {System.out.println("valueUnbound==>" + event.getName() + " : " + event.getValue());}}//javasession.setAttribute("user", new User());try {Thread.sleep(10000);} catch (Exception e) {}session.removeAttribute("user");
运行结果:
valueBound==>user : listener.domain.User@5f5220eevalueUnbound==>user : listener.domain.User@5f5220ee
f)HttpSessionActivationListener监听器,专用于监听JavaBean对象的钝化与激活:
钝化与激活概念:
1)当HttpSession不用时,但用在HttpSession的有效期中,这时将内存中的HttpSessio移到外存,叫钝化。
2)反之,将HttpSession由外存移到内存,叫激活。
JavaBean对象,感知自己何时被钝化,合适被激活,由web容器决定。
配置钝化激活时间:
针对所有项目:在tomcat的conf/context.xml进行配置.
针对单个项目:只需在此项目的META-INF/加入一个context.xml文件即可。
配置内容如下:
<?xml version="1.0" encoding="utf-8"?><Context><Manager className="org.apache.catalina.session.PersistentManager"maxIdleSwap="1"> //设置session钝化时间为1分钟<Store className="org.apache.catalina.session.FileStore"directory="target" /> //设置钝化文件目标存放目录</Manager></Context>
默认钝化文件.session的目标文件夹为: tomcat的work目录下。
code:
public class Stu implements HttpSessionActivationListener {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic void sessionDidActivate(HttpSessionEvent event) {System.out.println("sessionDidActivate");}@Overridepublic void sessionWillPassivate(HttpSessionEvent event) {System.out.println("sessionWillPassivate");}}
注意: 但凡是监听三个域对象,就需要在web.xml文件中配置,除外,无需要web.xml文件配置。
所以:
HttpSessionBindListener和HttpSessionActivationListener监听器无需在web.xml中进行配置。
4 监听器的工作过程和生命周期
开发过程:
a)写一个普通类实现对应的接口,即事件监听器
b)在web.xml文件中注册事件监听器
<!-- 事件源注册事件监听器,由容器完成 -->
<listener>
<listener-class>cn.itcast.web.listener.MyServletContextListener</listener-class>
</listener>
生命周期:
*空参构造(1次)->初始化(1次)->销毁化(1次),是一个单例的模式
在部署web应用是产生,即用户第一次访问之前已经产生,在重新部署web应用时,后销毁原监听器,再产生新的监听器
*5 案例
a)java.util.Timer定时器是以后台线程方式控制运行,它是线程安全,无需手工加锁
b)timer.schedule(new MyTimerTask(),0,5000);固定频度执行
c)Calendar c = Calendar.getInstance();
c.set(2011,10,6,10,30,40);
timer.schedule(new MyTimerTask(),c.getTime());指定时间执行
d)***Serlvet,Filter和Listener一样具有线程安全问题
e)当HttpSession过期时,Web容器负付执行对应的销毁方法,但是时间不精确
f)**Listener在Jsp或Servlet之前被执行
g)在线人数使用:context,第N个访问者使用:session
*补充:Timer类 ———— 定时器(线程安全的)
补充:timer.cancel() 方法,可以终止Timer定时器
public class TimerDemo {public static void main(String[] args) {Timer timer = new Timer();//延迟5秒进行,并每隔1秒执行一次任务//timer.schedule(new MyTimerTask(), 5000, 1000);//在2015年1月12日15时34分50秒执行一次任务Calendar calendar = Calendar.getInstance();calendar.set(2015, 0, 12, 15, 34, 50);timer.schedule(new MyTimerTask(), calendar.getTime());}}class MyTimerTask extends TimerTask {@Overridepublic void run() {System.out.println(new Date().toLocaleString());}}
监听器