在java web应用中,listener监听器似乎是必不可少的,常常用来监听servletContext、httpSession、servletRequest等域对象的创建、销毁以及属性的变化等等,可以在这些事件动作前后进行一定的逻辑处理。

比较常用的应用场景是利用监听器来初始化一些数据、统计在线人数、统计web应用浏览量等等。

这里所说的监听器实际上是servlet规范中定义的一种特殊类,需要实现特定的接口。

而我暂时先说其中三个用来监听域对象的,分别是servletContextListener、httpSessionListener、servletRequestListener。

这三个接口写法上实际是差不多的,都有两个分别代表了该域对象创建时调用和销毁时调用的方法,据我的理解,这三个对象最大的区别应该就是作用域不一样。

servletContext在整个应用启动到结束中生效,启动系统时创建这个对象,整个过程中这个对象是唯一的。

httpSession则是在一个session会话中生效,在一个session被创建直到失效的过程中都起作用,不过一个启动的应用中httpSession对象可以有多个,比如同一台电脑两个浏览器访问,就会创建两个httpSession对象。

而servletRequest是在一个request请求被创建和销毁的过程中生效,每发起一次请求就会创建一个新的servletRequest对象,比如刷新浏览器页面、点击应用的内链等等。

这三个监听器的写法基本如下伪代码所示:

首先创建一个监听器类实现相应的接口及方法:

package packageName;
public class ListenerName implements *Listener {

    @Override
    public void 对象创建时被调用的方法(相应的事件 arg0) {

    }

    @Override
    public void 对象销毁时被调用的方法(相应的事件 arg0) {

    }
}

然后在web.xml中注册:

 <listener>
    <listener-class>packageName.ListenerName</listener-class>
  </listener>

到这里,基本上这个监听器在启动web服务器以后就可以正常跑了,只是有时候我们还会在注册监听器的时候配置一些其他的。

比如配置servletContextListener的时候,可能会加上context-param参数:

<context-param>
     <param-name>paramName</param-name>
     <param-value>paramValue</param-value>
</context-param>

配置httpSessionListener的时候,可能会加上session超时:

<session-config>
     <session-timeout>1</session-timeout>
</session-config>

我感觉经过这样一整理后,就会发现起始监听器写起来还是很简单的,于是便模拟简单的实现了在线用户统计和应用访问量,基本代码如下:

首先是实现了servletContext

package webTest;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Date;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class ListenerTest1 implements ServletContextListener {

    @Override
    public void contextDestroyed(ServletContextEvent arg0) {

        System.out.println("contextDestroyed" + "," + new Date());
        Object count = arg0.getServletContext().getAttribute("count");
        File file = new File("count.txt");
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "utf-8");
            BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
            bufferedWriter.write(count.toString());
            bufferedWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        System.out.println("contextInitialized" + "," + new Date());
        File file = new File("count.txt");
        if (file.exists()) {
            try {
                FileInputStream fileInputStream = new FileInputStream(file);
                InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "utf-8");
                BufferedReader bReader = new BufferedReader(inputStreamReader);
                String count = bReader.readLine();
                System.out.println("历史访问次数:" + count);
                arg0.getServletContext().setAttribute("count", count);
                bReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

这里我把访问次数存在一个txt文件中,以便于持久化保存,当项目启动的时候,也就是创建servletContext对象的时候调用加载方法,从txt文件中读取历史访问量,然后使用setAttribute方法把这个数据存入到内存中。

之后当应用被关闭,servletContext对象被销毁的时候把内存中新的访问量数据覆盖写入到txt文件,以便于下次启动应用后继续读取之前的访问量。

然后使用servletRequestListener来实现web浏览量的变化,当然了,这里只是简单的实现,如果是要实现那种同一个用户刷新页面不增加浏览量的功能,还需要做更多的处理。

package webTest;
import java.util.Date;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;

public class ListenerTest3 implements ServletRequestListener {

    @Override
    public void requestDestroyed(ServletRequestEvent arg0) {
        System.out.println("requestDestroyed" + "," + new Date());
        System.out.println("当前访问次数:" + arg0.getServletContext().getAttribute("count"));
    }

    @Override
    public void requestInitialized(ServletRequestEvent arg0) {
        System.out.println("requestInitialized" + "," + new Date());
        Object count = arg0.getServletContext().getAttribute("count");
        Integer cInteger = 0;
        if (count != null) {
            cInteger = Integer.valueOf(count.toString());
        }
        System.out.println("历史访问次数::" + count);
        cInteger++;
        arg0.getServletContext().setAttribute("count", cInteger);
    }

}

这里同样是两个方法,在servletRequest对象被建立的时候调用初始化方法,从内存中读取servletContext对象的count属性,而后输出历史访问量。

同时在此基础上加一重新设置servletContext对象的count属性的内容,当servletRequest对象被销毁的时候调用销毁时的方法打印出当前浏览量,这样就简单的实现了web浏览的量的累加计数。

然后就是利用httpSessionListener来实现在线人数的统计:

package webTest;
import java.util.Date;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class ListenerTest2 implements HttpSessionListener {

    @Override
    public void sessionCreated(HttpSessionEvent arg0) {
        System.out.println("sessionCreated" + "," + new Date());
        Object lineCount = arg0.getSession().getServletContext().getAttribute("lineCount");
        Integer count = 0;
        if (lineCount == null) {
            lineCount = "0";
        }
        count = Integer.valueOf(lineCount.toString());
        count++;
        System.out.println("新上线一人,历史在线人数:" + lineCount + "个,当前在线人数有: " + count + " 个");
        arg0.getSession().getServletContext().setAttribute("lineCount", count);
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent arg0) {
        System.out.println("sessionDestroyed" + "," + new Date());
        Object lineCount = arg0.getSession().getServletContext().getAttribute("lineCount");
        Integer count = Integer.valueOf(lineCount.toString());
        count--;
        System.out.println("一人下线,历史在线人数:" + lineCount + "个,当前在线人数: " + count + " 个");
        arg0.getSession().getServletContext().setAttribute("lineCount", count);
    }

}

这里的代码都很简单,我想应该没有太多必要解释,需要说明的是,我这里把lineCount存放在servletContext对象中并不是唯一的方式,有兴趣的朋友可以尝试其他的方式,例如使用类属性。

这里的示例也已打包上传,需要的朋友可以自行下载运行。

链接:http://pan.baidu.com/s/1bZ2vx0

密码:ekb9

csdn下载:http://download.csdn.net/detail/tuzongxun/9761166

java中servletContextListener、httpSessionListener和servletRequestListener使用整理的更多相关文章

  1. 沉淀再出发:java中的CAS和ABA问题整理

    沉淀再出发:java中的CAS和ABA问题整理 一.前言 在多并发程序设计之中,我们不得不面对并发.互斥.竞争.死锁.资源抢占等等问题,归根到底就是读写的问题,有了读写才有了增删改查,才有了所有的一切 ...

  2. <Listener>servletContextListener、httpSessionListener和servletRequestListener使用整理

    在java web应用中,listener监听器似乎是不可缺少的.经常常使用来监听servletContext.httpSession.servletRequest等域对象的创建.销毁以及属性的变化等 ...

  3. Java中的Collections类

    转载:https://blog.csdn.net/yangxingpa/article/details/80515963 从[Java]Java中的Collections类——Java中升级版的数据结 ...

  4. JAVA中去掉空格经典整理

    JAVA中去掉空格经典整理 JAVA中去掉空格          1. String.trim() --------------trim()是去掉首尾空格           2.str.replac ...

  5. Java中实现多线程关键词整理

    Java中的Runable,Callable,Future,FutureTask,ExecutorService,Excetor,Excutors,ThreadPoolExcetor在这里对这些关键词 ...

  6. 各大公司Java面试题收录含答案(整理版)持续中....

    本文分为17个模块,分别是:Java基础.容器.多线程.反射.对象拷贝.Java web.异常.网络.设计模式.算法.Spring/Spring MVC.Spring Boot/Spring Clou ...

  7. java中的字符串相关知识整理

    字符串为什么这么重要 写了多年java的开发应该对String不陌生,但是我却越发觉得它陌生.每学一门编程语言就会与字符串这个关键词打不少交道.看来它真的很重要. 字符串就是一系列的字符组合的串,如果 ...

  8. java中的IO整理

    写在前面:本文章基本覆盖了java IO的全部内容,java新IO没有涉及,因为我想和这个分开,以突出那个的重要性,新IO哪一篇文章还没有开始写,估计很快就能和大家见面.照旧,文章依旧以例子为主,因为 ...

  9. java中反射学习整理

    转载请注明:http://blog.csdn.net/j903829182/article/details/38405735 反射主要是指程序能够訪问.检測和改动它本身的状态或行为的一种能力. jav ...

随机推荐

  1. 【转】C++易混知识点1: 指针常量和常量指针的区别,附有详细案例解释

    熟悉C++也已经有一些年头了,今天突然翻出当年浏览的书籍,对一些概念居然生疏了,指针常量和常量指针由于 指针 这一特殊的对象而变得难以区别.因此,在思考再三之后,决定写下该篇总结,加强对他们的区别: ...

  2. 【转】5 Best Place to Learn Linux – Linux Tutorial Sites

    Linux have amazed every tech guy and make them curious to hands on Linux. Many of us not feel Linux ...

  3. Hyperledger Fabric Chaincode for Operators——实操智能合约

    什么是Chaincode(智能合约)? chaincode是一个程序,它是使用Go语言编写的,最终在Java等其他编程语言中实现了指定的接口.chaincode运行在一个被背书peer进程独立出来的安 ...

  4. [TFRecord文件格式]基本介绍

    标准TensorFlow格式 TFRecords 觉得有用的话,欢迎一起讨论相互学习~Follow Me TFRecords可以允许你讲任意的数据转换为TensorFlow所支持的格式, 这种方法可以 ...

  5. 安装与配置cacti 0.8.8b

    cacti安装与配置 一.安装所需要的软件 Apache    安装Apache文档 Mysql      安装Mysql文档 Php       安装PHP文档 Rrdtool    安装rrdto ...

  6. Angular2学习笔记四(之Http通信)

    前言: 在这里,我描述三个场景,即系统的注册与登录,及登录后的操作: 1.注册场景,前端页面传入用户名密码,通过一个api接口传到后台,在后台对这用户及密码进行保存: 2.登录场景,前端用户传入用户名 ...

  7. ABP官方文档翻译 6.2.1 ASP.NET Core集成

    ASP.NET Core 介绍 迁移到ASP.NET Core? 启动模板 配置 启动类 模块配置 控制器 应用服务作为控制器 过滤器 授权过滤器 审计Action过滤器 校验过滤器 工作单元Acti ...

  8. Swing EDT引起的客户端卡死

    最近调试程序时发现,点击某个界面时会出现卡死的情况,出现的频率还是比较频繁的. 再次出现卡死的情况后,利用jvisualvm查看线程的运行情况,dump操作之后发现线程间出现了死锁: Found on ...

  9. 《EntrePreneur》发刊词

    I do not choose to be a common person. It is my right to be uncommon - if I can. I seek opportunity ...

  10. BZOJ 3879: SvT [虚树 后缀树]

    传送门 题意: 多次询问,给出一些后缀,求两两之间$LCP$之和 哈哈哈哈哈哈哈竟然$1A$了,刚才还在想如果写不好这道题下节数学就不上了,看来是上天让我上数学课啊 $Suffix\ Virtual\ ...