zoukankan      html  css  js  c++  java
  • 监听器

    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:

    //listener
    public class MyServletContextAttributeListener implements ServletContextAttributeListener {
    @Override
    public void attributeAdded(ServletContextAttributeEvent event) {
    System.out.println("attributeAdded==>" + event.getName() + " : " + event.getValue());
    }
    @Override
    public void attributeReplaced(ServletContextAttributeEvent event) {
    //注意:此时的getValue得到的是替换前的value值。
    System.out.println("attributeReplaced==>" + event.getName() + " : " + event.getValue());
    }
    @Override
    public void attributeRemoved(ServletContextAttributeEvent event) {
    System.out.println("attriattributeRemoved==>" + event.getName() + " : " + event.getValue());
    }
    }
    //java
    application.setAttribute("name", "jack");
    application.setAttribute("name", "杰克");
    application.removeAttribute("name");
    //输出结果:
    attributeAdded==>name : jack
    attributeReplaced==>name : jack
    attriattributeRemoved==>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;
    @Override
    public void requestDestroyed(ServletRequestEvent event) {
    System.out.println("requestDestroyed()");
    }
    @Override
    public 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 onload="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 {
    @Override
    public void sessionCreated(HttpSessionEvent event) {
    HttpSession session = event.getSession();
    //若为新创建的session
    if (session.isNew()) {
    System.out.println("sessionCreated, ID:" + session.getId());
    }
    }
    @Override
    public 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();
    @Override
    public void contextInitialized(ServletContextEvent event) {
    timer.schedule(new MyTimerTask(sessionList), 0, 1*1000);
    }
    @Override
    public void contextDestroyed(ServletContextEvent event) {
    //取消当前定时器
    timer.cancel();
    }
    
    @Override
    public void sessionCreated(HttpSessionEvent event) {
    HttpSession session = event.getSession();
    synchronized (sessionList) {
    sessionList.add(session);
    }
    System.out.println("Session产生:" + session.hashCode() + " : " + new Date().toLocaleString() );
    }
    @Override
    public 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;
    }
    @Override
    public 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:

    //listener
    public class User implements HttpSessionBindingListener {
    @Override
    public void valueBound(HttpSessionBindingEvent event) {
    System.out.println("valueBound==>" + event.getName() + " : " + event.getValue());
    }
    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
    System.out.println("valueUnbound==>" + event.getName() + " : " + event.getValue());
    }
    }
    //java
    session.setAttribute("user", new User());
    try {
    Thread.sleep(10000);
    } catch (Exception e) {
    
    }
    session.removeAttribute("user");
    

      

    运行结果:

    valueBound==>user : listener.domain.User@5f5220ee
    valueUnbound==>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;
    }
    @Override
    public void sessionDidActivate(HttpSessionEvent event) {
    System.out.println("sessionDidActivate");
    }
    @Override
    public 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 {
    @Override
    public void run() {
    System.out.println(new Date().toLocaleString());
    }
    }

     

  • 相关阅读:
    001.云桌面整体解决方案实施
    Netty基础招式——ChannelHandler的最佳实践
    架构设计之数据分片
    Go是一门什么样的语言?
    Jenkins汉化配置
    Window安装构建神器Jenkins
    uni-app&H5&Android混合开发三 || uni-app调用Android原生方法的三种方式
    如何使用Hugging Face中的datasets
    关于torch.nn.LSTM()的输入和输出
    pytorch中的nn.CrossEntropyLoss()计算原理
  • 原文地址:https://www.cnblogs.com/SkyGood/p/4224825.html
Copyright © 2011-2022 走看看