java中servletContextListener、httpSessionListener和servletRequestListener使用整理

在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>

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

首先是实现了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);
    }

}

这里的代码都非常easy。我想应该没有太多必要解释,须要说明的是。我这里把lineCount存放在servletContext对象中并非唯一的方式,有兴趣的朋友能够尝试其它的方式。比如使用类属性。

这里的演示样例也已打包上传。须要的朋友能够自行下载执行。

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

password:ekb9

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

时间: 2024-08-27 01:06:56

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

2.1号Java复习题目——Java中的字符串(基础知识整理)

Java中的字符串基础知识 作为程序开发当中,使用最频繁的类型之一,字符串有着与基础类型相同的地位,甚至在 JVM(Java 虚拟机)编译的时候会对字符串做特殊的处理,比如拼加操作可能会被 JVM 直接合成为一个最终的字符串,从而到达高效运行的目的. 1 String 特性 String 是标准的不可变类(immutable),对它的任何改动,其实就是创建了一个新对象,再把引用指向该对象: String 对象赋值之后就会在常量池中缓存,如果下次创建会判定常量池是否已经有缓存对象,如果有的话直接返

java中反射学习整理

转载请注明:http://blog.csdn.net/j903829182/article/details/38405735 反射主要是指程序可以访问,检测和修改它本身的状态或行为的一种能力. java中反射是一种强大的工具,它能够创建灵活的代码,这些代码可以在运行时装载,无须在组件之间进行链接.反射允许在编写与执行时,使程序能够接入到jvm中的类的内部信息,而不是源代码中选定的类协作的代码.这使反射成为构建灵活应用代码的主要工具.需要注意的是,如果使用不当,反射的成本会很高. package

java中的IO整理

写在前面:本文章基本覆盖了java IO的全部内容,java新IO没有涉及,因为我想和这个分开,以突出那个的重要性,新IO哪一篇文章还没有开始写,估计很快就能和大家见面.照旧,文章依旧以例子为主,因为讲解内容的java书很多了,我觉的学以致用才是真.代码是写出来的,不是看出来的. 最后欢迎大家提出意见和建议. [案例1]创建一个新文件 1 2 3 4 5 6 7 8 9 10 11 import java.io.*; class hello{     public static void mai

Java 中static的用法整理

static在java中属于使用相当频繁的一个关键字了,下面来总结一下它的用法,顺便梳理一下自己的知识树. 一.static变量: 静态变量在内存中只有一个拷贝,JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配. 实例变量,没创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响. static成员变量的初始化顺序按照定义的顺序进行初始化. 二.static方法: 首先要明确的一点,static所修饰的变量.方法.代码块等是在JVM中被直接装入内存的

[转]java中的字符串相关知识整理

字符串为什么这么重要 写了多年java的开发应该对String不陌生,但是我却越发觉得它陌生.每学一门编程语言就会与字符串这个关键词打不少交道.看来它真的很重要. 字符串就是一系列的字符组合的串,如果写过C/C++的应该就了解,在字符串的操作上会有许多操作的函数与类,用于简化代码的开发.一方面是因为字符串在代码中会频繁用到,另一方面是因为字符串的操作非常麻烦. 最初我知道String的特殊待遇就是在delphi中,因为String在delphi里是一个关键字存在,与其他的基本类型是不一样的.那时

Java中Iterator用法整理

迭代器(Iterator) 迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构.迭代器通常被称为"轻量级"对象,因为创建它的代价小. Java中的Iterator功能比较简单,并且只能单向移动: (1) 使用方法iterator()要求容器返回一个Iterator.第一次调用Iterator的next()方法时,它返回序列的第一个元素.注意:iterator()方法是java.lang.Iterable接口,被Collection继承

【转】 Java中的IO整理

写在前面:本文章基本覆盖了java IO的全部内容,java新IO没有涉及,因为我想和这个分开,以突出那个的重要性,新IO哪一篇文章还没有开始写,估计很快就能和大家见面.照旧,文章依旧以例子为主,因为讲解内容的java书很多了,我觉的学以致用才是真.代码是写出来的,不是看出来的. 最后欢迎大家提出意见和建议. [案例1]创建一个新文件 1 2 3 4 5 6 7 8 9 10 11 import java.io.*; class hello{     public static void mai

JAVA笔记整理(三),JAVA中的类和方法

类 类是JAVA中一个重要的概念,可以把类理解成一个对象的抽象,这个抽象的对象包含了变量(用来描述这个对象的属性)和方法(用来描述这个对象可以干什么),类中的各个成员之间可以相互调用(static修饰的成员不能访问没有static修饰的成员). 而每个类中又必须有一个或者多个构造方法,这个构造方法用来将这个抽象的对象实例化. 类的定义格式为 [修饰符] class 类名{ 构造函数; 成员变量; 方法; } 在类中的构造函数.成员变量和方法都可以是0个或者多个 类的修饰符可以使用public.f

JAVA笔记整理(四),JAVA中的封装

什么是封装 所谓的封装就是把数据项和方法作为一个独立的整体隐藏在对象的内部,具体的实施细节不对外提现,仅仅保留有限的外部接口,封装外的用户只能通过接口来进行操作.就好比开启一台电脑需要进行很多个步骤,电源供电.BIOS自检.查找硬件等等一系列动作,而我们只需要按下开机按钮,其余的动作都是电脑内部完成的,这里就可以看作是电脑对启动的一系列动作进行了封装,给提供了开机按钮供我们调用. 为何需要封装 首先,从程序安全性上来说,暴露在外面的细节被隔离掉,要想修改内部的数据,必须使用提供的特定方法,而这些