?
本文查阅方法:
??? 1、查阅目录 —— 查阅本文目录,确定想要查阅的目录标题
??? 2、快捷“查找” —— 在当前浏览器页面,按键 “Ctrl+F” 按键组合,开启浏览器的查找功能,
???????????? 在查找搜索框中 输入需要查阅的 目录标题,便可以直接到达 标题内容 的位置。
??? 3、学习小结 —— 文中的学习小结内容,是笔者在学习之后总结出的,开发时可直接参考其进行应用开发的内容, 进一步加快了本文的查阅 速度。(水平有限,仅供参考。)
?
?
?
?
??
?
本文目录
?
????学习小结
?
????1、监听器的概念与原理图解
?
????2、观察者设计模式(Observer设计模式?)
?
????3、Servlet监听器?
?
????4、监听servletContext域对象创建和销毁?
?
????5、编写?Servlet?监听器?
?
????6、监听HttpSession域对象创建和销毁?
?
????7、监听HttpRequest域对象创建和销毁?
?
????8、Servlet监听器应用案例——?统计当前在线人数
?
????9、Servlet监听器应用案例——?自定义session扫描器控制其主动销毁
?
????10、监听三个域对象属性变化?
?
????11、attributeAdded?方法
?
????12、attributeRemoved?方法?
?
????13、attributeReplaced?方法?
?
????14、感知?Session?绑定的事件监听器?
?
????15、HttpSessionBindingListener接口?
?
????16、HttpSessionActivationListener接口?
?
????17、Servlet监听器应用案例——?定时器模拟定时发邮件
?
????18、Servlet监听器应用案例——?显示登陆用户列表,并实现踢人功能。
?
?
?
????《Servlet?知识详解(一)之??——??ServletContext对象?和?ServletConfig对象?学习笔记》
?
????????地址:?http://even2012.iteye.com/blog/1838063
?
????《Servlet?知识详解(二)之??——??Request对象?和?Response对象?学习笔记》
?
????????地址:http://even2012.iteye.com/blog/1838099
?
????《Servlet?知识详解(三)之??——??Cookie对象?和?Session对象??学习笔记》
?
????????地址:http://even2012.iteye.com/blog/1838128
????《Servlet?知识详解(四)之??——? Filter对象 过滤器? 学习笔记》
?
????????地址:http://even2012.iteye.com/blog/1963466
????《Servlet?知识详解(五)之??——? Listener对象 监听器? 学习笔记》
?
????????地址:http://even2012.iteye.com/blog/1963467
?
?
????学习小结
?
?
?
?
?
?
1、监听器的概念与原理图解
?
????????监听器就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行。
?
????面试题:请描述一下java事件监听机制。
?
????????(1) Java的事件监听机制涉及到三个组件:事件源、事件监听器、事件对象
?
????????(2) 当事件源上发生操作时,它将会调用事件监听器的一个方法,并在调用这个方法时,会传递事件对象过来。
?
????????(3) 事件监听器由开发人员编写,开发人员在事件监听器中,通过事件对象可以拿到事件源,从而对事件源上的操作进行处理。
?
??
?
?
?
?
?
监听器典型案例:监听window窗口的事件监听器
?
?
?
?
?
?
2、观察者设计模式(Observer设计模式 )
?
?
?
class?Person{
?
?
?
??????private?PersonListener?listener;
?
?
?
??????public?void?registerListener(PersonListener?listener){
?
????????????this.listener?=?listener;
?
??????}
?
?
?
??????public?void?run(){
?
????????????if(listener!=null){
?
??????????????????Even?even?=?new?Even(this);
?
??????????????????this.listener.dorun(even);
?
????????????}
?
????????????System.out.println("runn!!");
?
??????}
?
?
?
??????public?void?eat(){
?
????????????if(listener!=null){
?
??????????????????Even?e?=?new?Even(this);
?
??????????????????this.listener.doeat(e);
?
????????????}
?
????????????System.out.println("eat!!");
?
??????}
?
}
?
?
?
// 监听器接口:Interface?
?
interface?PersonListener{
?
?
?
??????public?void?dorun(Even?even);
?
?????
?
??????public?void?doeat(Even?even);??
?
?
?
}
?
?
?
// 代表事件源的对象
?
class?Even{
?
??????????private?Person?person;?????????
?
??????????public?Even()?{
?
????????????????super();
?
????????????????//?TODO?Auto-generated?constructor?stub
?
??????????}
?
?????????
?
??????????public?Even(Person?person)?{
?
????????????????super();
?
????????????????this.person?=?person;
?
??????????}
?
?????????
?
??????????public?Person?getPerson()?{
?
????????????????return?person;
?
??????????}
?
?????????
?
??????????public?void?setPerson(Person?person)?{
?
????????????????this.person?=?person;
?
??????????}??
?
}
?
?
?
?// 实现监听器功能的类
?
class?MyListener1?implements?PersonListener{
?
?
?
??????public?void?doeat(Even?even)?{
?
????????????System.out.println(even.getPerson()+"你天天吃,你就知道吃,你猪啊!!");
?
??????}
?
?????
?
??????public?void?dorun(Even?even)?{
?
????????????System.out.println(even.getPerson()+"你吃完就跑,有病!!");?
?
??????}?
?
}
?
??
?
????观察者模式应用案例:餐馆有多部点菜设备,和一台已点菜单打印机,要求每台点菜设备点完菜,打印机都会自动打印出菜单给厨房,请问如何设计该自动打印系统 。
?
方案一:定时器扫描菜单数据库(缺点:会造成CUP空转——没有点菜的时间也会扫描数据库。)
?
方案二:采用观察者模式——每次点菜设备执行点菜操作后,都会触发监听器,使打印机主动打印菜单。
?
??
?
?
?
?
3、Servlet监听器?
?
????????在Servlet规范中定义了多种类型的监听器,它们用于监听的事件源分别为?ServletContext,?HttpSession?和?ServletRequest?这三个域对象。?
?
????????Servlet规范针对这三个对象上的操作,又把这多种类型的监听器划分为三种类型。
?
????????????(1) 监听三个域对象创建和销毁的事件监听器
?
????????????(2) 监听域对象中属性的增加和删除的事件监听器
?
????????????(3) 监听绑定到?HttpSession?域中的某个对象的状态的事件监听器。(查看API文档)
?
?
?
?
??
?
4、监听servletContext域对象创建和销毁?
?
ServletContextListener?接口用于监听?ServletContext?对象的创建和销毁事件。
?
????????(1) 当?ServletContext?对象被创建时,激发contextInitialized?(ServletContextEvent?sce)方法
?
????????(2) 当?ServletContext?对象被销毁时,激发contextDestroyed(ServletContextEvent?sce)方法。
?
?
?
提问,servletContext域对象何时创建和销毁:
?
创建:服务器启动时会针对每一个web应用创建servletcontext
?
销毁:服务器关闭前会先关闭代表每一个web应用的servletContext
?
?
?
?
??
?
5、编写?Servlet?监听器?
?
????????和编写其它事件监听器一样,编写servlet监听器也需要实现一个特定的接口,并针对相应动作覆盖接口中的相应方法。
?
????????和其它事件监听器略有不同的是,servlet监听器的注册不是直接注册在事件源上,而是由WEB容器负责注册,开发人员只需在web.xml文件中使用<listener>标签配置好监听器,web容器就会自动把监听器注册到事件源中。
?
????????一个?web.xml?文件中可以配置多个?Servlet?事件监听器,web?服务器按照它们在?web.xml?文件中的注册顺序来加载和注册这些?Serlvet?事件监听器。
?
Demo样例:?
?
??<listener>
?
????????<listener-class>cn.itcast.web.listener.exapmle.SendMailTimer</listener-class>
?
??</listener>
?
?
?
?
??
?
6、监听HttpSession域对象创建和销毁?
?
????(1) HttpSessionListener接口用于监听HttpSession的创建和销毁
?
????????(a) 创建一个Session时,sessionCreated(HttpSessionEvent?se)?方法将会被调用。
?
????????(b) 销毁一个Session时,sessionDestroyed?(HttpSessionEvent?se)?方法将会被调用。
?
?
?
????(2) Session域对象创建和销毁的时机
?
????????创建:用户第一次访问时,服务器创建session
?
????????销毁:如果用户的session?30分钟没有使用,服务器就会销毁session,我们在web.xml里面也可以配置session失效时间
?
?
?
????(3) 配置Session失效时间:
?
??????????<session-config>
?
????????????????<session-timeout>1</session-timeout>
?
??????????</session-config>
?
?
?
????(4) 配置Session对象的非活动时间:
?
????????需要对服务器进行配置:将下面的代码创建一份context.xml文件,放到META-INF文件夹下面(会被发布到Tomcat服务器的conf\Catalina\localhost)
?
????????<Context>
?
????????????<Manager?className="org.apache.catalina.session.PersistentManager"?maxIdleSwap="1">
?
????????????????<Store?className="org.apache.catalina.session.FileStore"?directory="it315"/>
?
????????????</Manager>
?
????????</Context>?
?
?
?
?
?
7、监听HttpRequest域对象创建和销毁?
?
????(1) ServletRequestListener?接口用于监听ServletRequest?对象的创建和销毁。
?
?????? ??(a) Request?对象被创建时,监听器的requestInitialized方法将会被调用。
?
??????? ?(b) Request 对象被销毁时,监听器的requestDestroyed方法将会被调用。
?
?????(2) servletRequest域对象创建和销毁的时机:
?
?????????(a) 创建:用户每一次访问,都会创建一个reqeust
?
?????????(b) 销毁:当前访问结束,request对象就会销毁
?
?
?
?
??
?
8、Servlet监听器应用案例—— 统计当前在线人数
?
Demo样例:CountNumListener.java
?
public?class?CountNumListener?implements?HttpSessionListener?{?
?
??????public?void?sessionCreated(HttpSessionEvent?se)?{
?
????????????ServletContext?context?=?se.getSession().getServletContext();
?
????????????Integer?count?=?(Integer)?context.getAttribute("count");
?
????????????if(count==null){
?
??????????????????count?=?1;
?
??????????????????context.setAttribute("count",?count);
?
????????????}else{
?
??????????????????count++;
?
??????????????????context.setAttribute("count",?count);
?
????????????}
?
??????}
?
?????
?
??????public?void?sessionDestroyed(HttpSessionEvent?se)?{
?
????????????ServletContext?context?=?se.getSession().getServletContext();
?
????????????Integer?count?=?(Integer)?context.getAttribute("count");
?
????????????count--;
?
????????????context.setAttribute("count",?count);?
?
??????}
?
}
?
?
?
?
?
?
9、Servlet监听器应用案例—— 自定义session扫描器控制其主动销毁
?
Demo样例:SessionScanner.java
?
????public?class?SessionScanner?implements?HttpSessionListener,ServletContextListener?{?
?
??????????????private?List<HttpSession>?list?=?Collections.synchronizedList(new?LinkedList<HttpSession>());
?
??????????????private?Object?lock?=?new?Object();
?
?????????????
?
??????????????//?Web应用启动时,启动定时器!
?
??????????????public?void?contextInitialized(ServletContextEvent?sce)?{????
?
????????????????????Timer?timer?=?new?Timer();
?
?????????????????
?
????????????????????//?定时器任务:每隔30秒就扫描一次集合:是否有Session对象超时,若超时就会被处理(删除)
?
????????????????????timer.schedule(new?MyTask(list,lock),?0,?30*1000);
?
?????????????}
?
?????
?
??????????//?Session创建的时候,就被添加到集合里面,进行控制管理
?
??????????public?void?sessionCreated(HttpSessionEvent?se)?{
?
????????????????HttpSession?session?=?se.getSession();
?
????????????????System.out.println(session?+?"被创建了!!");
?
????????????????synchronized?(lock)?{??//锁旗标——防止定时器中caozuo.html" target="_blank">删除操作?发生“并发修改异常”。
?
??????????????????????list.add(session);
?
????????????????}
?
??????????}
?
??????????public?void?sessionDestroyed(HttpSessionEvent?se)?{
?
????????????????System.out.println(se.getSession()?+?"被销毁了");
?
??????????}
?
?????
?
??????????public?void?contextDestroyed(ServletContextEvent?sce)?{
?
????????????????//?TODO?Auto-generated?method?stub
?
??????????}
?
????}
?
?
?
????//?定时器任务
?
????class?MyTask?extends?TimerTask{
?
?????
?
??????????private?List?list;
?
??????????private?Object?lock;?//接收锁旗标——?防止定时器中删除操作?发生“并发修改异常”。
?
??????????public?MyTask(List?list,Object?lock){
?
????????????????this.list?=?list;
?
????????????????this.lock?=?lock;
?
??????????}
?
?????
?
??????@Override
?
??????public?void?run()?{
?
????????????System.out.println("定时器执行!!");
?
????????????synchronized?(this.lock)?{
?
??????????????????ListIterator?it?=?list.listIterator();//?此处若使用Iterator,下面在删除操作时,就会发生“并发修改异常”。
?
??????????????????while(it.hasNext()){
?
????????????????????????HttpSession?session?=?(HttpSession)?it.next();
?
????????????????????????if((System.currentTimeMillis()-session.getLastAccessedTime())>30*1000){
?
??????????????????????????????session.invalidate();
?
??????????????????????????????//list.remove(session);??//并发修改异常:ConcurrentModificationException
?
??????????????????????????????it.remove();
?
????????????????????????}
?
??????????????????}
?
????????????}
?
??????}
?
}
?
?
?
?
??
?
10、监听三个域对象属性变化?
?
????????Servlet规范定义了监听?ServletContext,?HttpSession,?HttpServletRequest?这三个对象中的属性变更信息事件的监听器。
?
????????这三个监听器接口分别是ServletContextAttributeListener ,HttpSessionAttributeListener?,ServletRequestAttributeListener
?
????????这三个接口中都定义了三个方法来处理被监听对象中的属性的增加,删除和替换的事件,同一个事件在这三个接口中对应的方法名称完全相同,只是接受的参数类型不同。?
?
?
?
?
??
?
11、attributeAdded?方法
?
? ????当向被监听器对象中增加一个属性时,web容器就调用事件监听器的?attributeAdded?方法进行相应,这个方法接受一个事件类型的参数,监听器可以通过这个参数来获得正在增加属性的域对象和被保存到域中的属性对象?
?
????各个域属性监听器中的完整语法定义为:
?
????????public?void?attributeAdded(ServletContextAttributeEvent?scae)?
?
????????public?void?attributeReplaced(HttpSessionBindingEvent??hsbe)?
?
????????public?void?attributeRmoved(ServletRequestAttributeEvent?srae)
?
?
?
?
??
?
12、attributeRemoved?方法?
?
????当删除被监听对象中的一个属性时,web?容器调用事件监听器的这个方法进行相应处理
?
????????各个域属性监听器中的完整语法定义为:
?
????????????public?void?attributeRemoved(ServletContextAttributeEvent?scae)?
?
????????????public?void?attributeRemoved?(HttpSessionBindingEvent??hsbe)?
?
????????????public?void?attributeRemoved?(ServletRequestAttributeEvent?srae)
?
?
?
?
??
?
13、attributeReplaced?方法?
?
????当监听器的域对象中的某个属性被替换时,web容器调用事件监听器的这个方法进行相应处理
?
????????各个域属性监听器中的完整语法定义为:
?
????????????????public?void?attributeReplaced(ServletContextAttributeEvent?scae)?
?
????????????????public?void?attributeReplaced?(HttpSessionBindingEvent??hsbe)?
?
????????????????public?void?attributeReplaced?(ServletRequestAttributeEvent?srae)
?
?
?
?
??
?
14、感知?Session?绑定的事件监听器?
?
????????保存在?Session?域中的对象可以有多种状态:
?
????????????(1) 绑定到??Session?中;
?
????????????(2) 从?Session?域中解除绑定;
?
????????????(3) 随?Session?对象持久化到一个存储设备中(钝化);
?
????????????(4) 随?Session?对象从一个存储设备中恢复(活化)
?
????????Servlet?规范中定义了两个特殊的监听器接口来帮助?JavaBean?对象了解自己在?Session?域中的这些状态:HttpSessionBindingListener接口和HttpSessionActivationListener接口?,实现这两个接口的类不需要?web.xml?文件中进行注册
?
?
?
?
??
?
15、HttpSessionBindingListener接口?
?
????????实现了HttpSessionBindingListener接口的?JavaBean?对象可以感知自己被绑定到?Session?中和从?Session?中删除的事件
?
????????当对象被绑定到?HttpSession?对象中时,web?服务器调用该对象的??void?valueBound(HttpSessionBindingEvent?event)?方法
?
????????当对象从?HttpSession?对象中解除绑定时,web?服务器调用该对象的?void?valueUnbound(HttpSessionBindingEvent?event)方法
?
?
?
?
??
?
16、HttpSessionActivationListener接口?
?
????????实现了HttpSessionActivationListener接口的?JavaBean?对象可以感知自己被活化和钝化的事件
?
????????当绑定到?HttpSession?对象中的对象将要随?HttpSession?对象被钝化之前,web?服务器调用如下方法sessionWillPassivate(HttpSessionBindingEvent?event)?方法
?
????????当绑定到?HttpSession?对象中的对象将要随?HttpSession?对象被活化之后,web?服务器调用该对象的?void?sessionDidActive(HttpSessionBindingEvent?event)方法
?
?【备注:JavaBean对象只有实现了Serializable接口后,才能被持久化到硬盘。】
?
?
?
??【小技巧:??配置Session对象的非活动时间:需要对服务器进行配置:将下面的代码创建一份context.xml文件,放到META-INF文件夹下面(会被发布到Tomcat服务器的conf\Catalina\localhost)
?
????<Context>
?
????????<Manager?className="org.apache.catalina.session.PersistentManager"?maxIdleSwap="1">
?
????????????<Store?className="org.apache.catalina.session.FileStore"?directory="it315"/>
?
????????</Manager>
?
????</Context>
?
????】
?
?
?
?
?
?
17、Servlet监听器应用案例—— 定时器模拟定时发邮件
?
Demo样例:SendMailTimer.java
?
?
?
public?class?SendMailTimer?implements?ServletContextListener?{?
?
??public?void?contextInitialized(ServletContextEvent?sce)?{
?
????Timer?timer?=?new?Timer();
?
????Calendar?c?=?Calendar.getInstance();
?
????c.set(2011,?3,?7,?11,?54,?44);
?
????timer.schedule(new?TimerTask(){
?
??????@Override
?
??????public?void?run()?{
?
????????System.out.println("发邮件!!!");????????
?
??????}
?
????},?c.getTime());
?
??}
?
?
?
??public?void?contextDestroyed(ServletContextEvent?sce)?{
?
????//?TODO?Auto-generated?method?stub
?
??}
?
}
?
?
?
?
?
?
18、Servlet监听器应用案例—— 显示登陆用户列表,并实现踢人功能。
?
?思路:
?
????????(1) 收集登录用户——通过HttpSessionAttributeListener监听器将保存通过登录验证用户的Session对象添加到集合中;
?
????????(2) 踢出非法用户——在集合中找到非法用户的Session对象,将其销毁。
?
?
?
Demo样例:UserListener.java
?
?
?
public?class?UserListener?implements?HttpSessionAttributeListener?{
?
?
?
??????public?void?attributeAdded(HttpSessionBindingEvent?se)?{????
?
????????????Map?map?=?(Map)?se.getSession().getServletContext().getAttribute("map");
?
????????????if(map==null){
?
??????????????????map?=?new?HashMap();
?
??????????????????se.getSession().getServletContext().setAttribute("map",?map);
?
????????????}
?
?????????
?
????????????Object?object?=?se.getValue();
?
????????????if(object?instanceof?User){
?
??????????????????User?user?=?(User)?object;
?
??????????????????map.put(user.getUsername(),?se.getSession());
?
????????????}????
?
??????}
?
?
?
??????public?void?attributeRemoved(HttpSessionBindingEvent?se)?{
?
????????????//?TODO?Auto-generated?method?stub????
?
??????}
?
?????
?
??????public?void?attributeReplaced(HttpSessionBindingEvent?se)?{
?
????????????//?TODO?Auto-generated?method?stub????
?
??????}
?
}?
?
??
?
Demo样例:踢出非法用户KickServlet.java?
?
public?class?KickServlet?extends?HttpServlet?{
?
?
?
??public?void?doGet(HttpServletRequest?request,?HttpServletResponse?response)
?
??????throws?ServletException,?IOException?{
?
?
?
????????String?username?=?request.getParameter("username");
?
????????username?=?new?String(username.getBytes("iso8859-1"),"UTF-8");
?
?????
?
????????Map?map?=?(Map)?this.getServletContext().getAttribute("map");
?
????????HttpSession?session?=?(HttpSession)?map.get(username);
?
????????if(session!=null){
?
??????????????session.invalidate();
?
??????????????map.remove(username);
?
????????}
?
?
?
????????response.sendRedirect("/day21_kick/listuser.jsp");
?
??}
?
?
?
??public?void?doPost(HttpServletRequest?request,?HttpServletResponse?response)
?
??????throws?ServletException,?IOException?{
?
????doGet(request,?response);
?
??}
?
}
?
?
?
?
?
敬请评论
(1)若您觉得本文 有用处? —— 请留言评论,以坚定其他 IT童鞋 阅读本文的信心。
(2)若您觉得本文 没用处? —— 请留言评论,笔者将会改进不足,以便为大家整理更加好用的笔记。
?
?
?
?
?
?