Servlet过滤器简介

来源:互联网 发布:java conditionobject 编辑:程序博客网 时间:2024/06/05 10:48

 

很早之前,Servlet API就已成为企业应用开发的重要工具。现在,Servlet中的过滤器和监听器功能则是对J2EE体系的一个补充。过滤器使得Servlet开发者能够在请求到达Servlet之前截取请求,在Servlet处理请求之后修改应答;而Servlet监听器可以监听客户端的请求、服务端的操作,通过监听器,可以自动激发一些操作,如监听应用的启动和停止等。本章将接着介绍Servlet过滤器和监听器的相关知识以及在实际开发中如何使用这些技术。

本章重点:

  ● Servlet过滤器简介

  ● Servlet过滤器的实现

  ● Servlet过滤文本信息

  ● Servlet监听器简介

 Servlet过滤器简介

Servlet过滤器是小型的Web组件,能拦截请求和响应,以便查看、提取或以某种方式操作正在客户机和服务器之间交换的数据。过滤器是封装了一些功能的Web组件,这些功能虽然很重要,但是对于处理客户机请求或发送响应来说不是决定性的。典型的例子包括记录关于请求和响应的数据、处理安全协议、管理会话属性等。

一个过滤器可以被关联到任意多个资源,一个资源也可以关联到任意多个过滤器。

 Web资源与过滤器相关联

关联到同一个资源的过滤器形成一个过滤器链。例如,对S2进行访问时,F1、F2、F3就形成了一个过滤器链,客户要访问资源S2,就要经过F1过滤器,然后是F2、F3,最后才是要访问的资源。如果在经过上面这3个过滤器时出现了错误或者被禁止访问,客户的请求就无法到达资源S2。在Servlet过滤器中,这个过滤器传递的过程是通过FilterChain.dofilter()方法实现的,当过滤器链到达末尾时,这个方法调用请求的资源。建立一个过滤器,一般需要下面4个步骤:

(1)建立一个实现Filter接口的类。这个类需要3个方法,即doFilter、init和destroy。doFilter方法包含主要的过滤代码(见第(2)步),在init方法中进行一些初始化的设置,而destroy方法进行清除过滤器占用的资源。

(2)在doFilter方法中放入过滤行为。doFilter方法的第一个参数为ServletRequest对象,为过滤器提供了对进入的信息(包括表单数据、cookie和HTTP请求头)的完全访问。第二个参数为ServletResponse,通常在简单的过滤器中忽略此参数。最后一个参数为FilterChain,用来调用过滤器链中下一个过滤器或者在到达过滤器末尾时调用Servlet或JSP页。

(3)调用FilterChain对象的doFilter方法。Filter接口的doFilter方法将一个FilterChain对象作为它的一个参数。在调用此对象的doFilter方法时,激活下一个相关的过滤器。如果没有另一个过滤器与Servlet或JSP页面关联,则Servlet或JSP页面被激活。

(4)对相应的Servlet和JSP页面注册过滤器。在部署描述符文件(web.xml)中使用filter和filter-mapping元素对需要进行过滤的资源进行配置。

  实现一个Servlet过滤器

Servlet过滤器API包含3个简单的接口,即Filter、FilterChain和FilterConfig,它们位于javax.servlet包中。从编程的角度看,过滤器类将实现Filter接口,然后使用这个过滤器类中的FilterChain和FilterConfig接口。该过滤器类的一个引用将传递给FilterChain对象,以允许过滤器将控制权传递给过滤器链中的下一个过滤器或者资源。FilterConfig对象将由容器提供给过滤器,以允许访问该过滤器的初始化数据。

14.2.1  编写实现类的程序

下面是一个简单的Servlet过滤器的例子,其中将获取一个Web服务器给客户提供服务需要的时间,也就是响应时间。

【本节示例参考:资料光盘\源代码\第14章\14-2\Servlet.java】

【实例14-1】这是一个实现类的程序,主要是使用过滤器处理请求,在处理时可能要耗费很多    时间。

程序14-1  Servlet.java

01  package cn.ac.ict.Filter;

02  import java.io.IOException;

03  import java.io.PrintWriter;

04  import java.io.StringWriter;

05  import java.util.Date;

06  import javax.servlet.*;

07  public class ResponseTimeFilter implementsFilter {

08      private FilterConfigfilterConfig = null;

09      public void init(FilterConfigconfig) throws ServletException {//初始化函数

10         this.filterConfig = config;

11      }

12      public voiddoFilter(ServletRequest request, ServletResponse response,FilterChain chain)throws IOException, ServletException {

13          DatestartTime, endTime;

14          doubletotalTime;

15          startTime= new Date();

16         StringWriter sw = new StringWriter();

17         PrintWriter writer = new PrintWriter(sw);

18         writer.println();

19         writer.println("ResponseTimeFilter Before call chain.doFilter");

20         chain.doFilter(request, response);                   //将请求转发给过滤器链中下一个资源

21          //下面是资源的响应时间

22          //下面计算开始时间和结束时间的差,也就是响应时间

23         endTime = new Date();

24         totalTime = endTime.getTime() - startTime.getTime();

25         totalTime = totalTime / 1000; //将毫秒时间转换为以秒为单位

26         writer.println("ResponseTimeFilter Before call chain.doFilter");

27         writer.println("===============");

28         writer.println("Total elapsed time is: " + totalTime + "seconds." );

29         writer.println("===============");

30  filterConfig.getServletContext().log(sw.getBuffer().toString());   //将信息输出到日志中

31         writer.flush();

32      }

33      public void destroy() {

34         this.filterConfig = null;

35      }

36      public FilterConfiggetFilterConfig() {

37          returnnull;

38      }

39      public voidsetFilterConfig(FilterConfig config) {

40      }

41  }

【深入学习】当容器第一次加载该过滤器时,init()方法将被调用。该类在这个方法中包含了一个指向FilterConfig对象的引用。过滤器的大多数时间都消耗在执行过滤操作上,第20行中的doFilter()方法被容器调用,同时传入分别指向这个请求/响应链中的ServletRequest、ServletResponse和FilterChain对象的引用。然后过滤器就有机会处理请求,将处理任务传递给链中的下一个资源(通过调用FilterChain对象引用上的doFilter()方法),之后在处理控制权返回该过滤器时处理响应。

14.2.2  配置发布Servlet过滤器

发布Servlet过滤器时,必须在web.xml文件中加入<filter>和<filter-mapping>元素,其中,<filter>元素用来定义一个过滤器,在本例中使用了如下代码:

        <filter>

           <filter-name>Request Response Time</filter-name>

       <filter-class>cn.ac.ict.Filter.ResponseTimeFilter</filter-class>

        </filter>

以上代码中,<filter-name>指定过滤器的名字,<filter-class>指定过滤器的完整类名,也可以在<filter>元素中内嵌<init-param>元素来为过滤器提供初始化参数。

<filter-mapping>元素用于将过滤器和URL关联,本例中的代码如下:

       <filter-mapping>

           <filter-name>Request Response Time</filter-name>

           <url-pattern>/ShowCounter.jsp</url-pattern>

       </filter-mapping>   

当客户请求的URL和<url-pattern>指定的URL相匹配时,就会触发ResponseTimeFilter过滤器,这里的<filter-name>元素的值和<filter>元素中的<filter-name>值应该相同。

说明:如果希望Servlet过滤器能过滤所有的客户请求,可以将<url-pattern>的值设置为/*。

准备好上面的文件后,按照如下步骤即可发布这个Servlet过滤器。

(1)编译ResponseTimeFilter类,编译时,需要将Java Servlet API的包servlet-api.jar放到类路径中,编译后的类放到本章Web应用的WEB-INF\classes目录下,并且目录结构要与包的结构一致。

(2)在web.xml文件中按照上面说明的方法配置这个过滤器。

(3)为了观察这个过滤器的日志,应确保在server.xml文件的localhost对应的host元素中配置了如下的logger元素:

        <LoggerclassName="org.apache.catalina.logger.FileLogger"

                directory="logs"  prefix="localhost_log."suffix=".txt"

           timestamp="true"/>

以上内容在默认情况下都是配置好的。

(4)启动Tomcat,在浏览器地址栏中输入http://localhost:8080/14/ShowCounter.jsp,这时在<TOMCAT_HOME>\logs\localhost_log.2009-05-24.txt文件中会生成如下的日志信息:

2009-05-26 23:03:42 StandardContext[/15]

ResponseTimeFilter Before call chain.doFilter

ResponseTimeFilter Before call chain.doFilter

===============

Total elapsed time is: 0.0 seconds.

===============

说明:本例中访问的ShowCounter.jsp页面在本章的监听器部分介绍,如果读者不想跳跃着查看这个文件,可以尝试修改过滤器关联的URL,使得它可以过滤读者指定的资源。

14.3  ServletRequest和ServletResponse的包装类

Servlet过滤器能够对客户的请求和响应进行包装,并根据自定义的行为对请求和响应进行修改,这就是通过使用ServletRequest和ServletResponse的包装类——HttpServletRequestWrapper和HttpServletResponseWrapper类来实现的。这两个类提供了所有request和response方法的默认实现,并且默认地代理了所有对原有request和response的调用。这也意味着,要改变一个方法的行为只需要从封装类继承并重新实现一个方法即可。

  ● ServletRequestWrapper类:是ServletRequest的包装类,实现了ServletRequest接口,并对其方法提供了默认实现。

  ● ServletResponseWrapper类:是ServletResponse的包装类,实现了ServletResponse接口,并对其方法提供了默认实现。

14.4  用Servlet过滤器过滤文本信息

在14.3节中简单介绍了ServletRequest和ServletResponse的包装类,它们在过滤器设计中会经常被用到。本节将介绍一个使用HttpServletResponseWrapper类的例子,客户输入的内容会被检查,如果存在不允许出现的信息,就会被过滤掉,而被替换成其他的字符。在这个例子中,客户输入用户名并发布自己的留言信息,然后提交给服务器,服务器再将这些信息反馈给客户。如果客户的留言中有指定的字符串,就会调用过滤器将这个字符串替换掉。

14.4.1  输出流管理类

在Servlet输出时可以选择不同的输出流,将它们集合在一起,即可很容易地对这些流进行管理,使用时也会更方便。如何使用输出流管理类,可以看下面的代码。

【本节示例参考:资料光盘\源代码\第14章\14-4\ByteArrayPrintWriter.java】

【实例14-2】将输出流进行方法的实例化,方便以后程序的调用。

程序14-2  ByteArrayPrintWriter.java

01  package cn.ac.ict;

02  import java.io.ByteArrayOutputStream;

03  import java.io.PrintWriter;

04  import javax.servlet.ServletOutputStream;

05  public class ByteArrayPrintWriter {

06      private ByteArrayOutputStreambaos = new ByteArrayOutputStream();

07      private PrintWriter pw = newPrintWriter(baos);

08      private ByteArrayOutputStreamsos = new ByteArrayOutputStream();

09      publicByteArrayPrintWriter(ByteArrayOutputStream aos) {

10          this.baos= aos;

11      }

12      //一个为空的构造方法

13      public ByteArrayPrintWriter(){

14      }

15      //使用字符输出流时调用获取输出流

16      public PrintWritergetWriter() {

17          return pw;

18      }

19      //使用字节输出流时调用获取输出流

20      public ByteArrayOutputStreamgetStream() {

21          returnsos;

22      }

23      byte[] toByteArray() {

24          returnbaos.toByteArray();

25      }

26  }

【深入学习】在第6、7、8行共定义了3个对象,一个是用字符流输出的,一个是用字节流输出的,但是它们最终都套接到类型为ByteArrayOutputStream的对象上,这个对象为它们提供了原始输出数据。

14.4.2  编写Servlet过滤器

前面编写了需要使用的辅助类,接下来即可开发进行实际过滤功能的文本过滤器。

【实例14-3】如何实现文本过滤器,代码(TextModifierFilter.java)如下:

程序14-3  TextModifierFilter.java

01  package cn.ac.ict;

02  import java.io.IOException;

03  import java.io.PrintWriter;

04  import java.util.Locale;

05  import javax.servlet.Filter;

06  import javax.servlet.FilterChain;

07  import javax.servlet.FilterConfig;

08  import javax.servlet.ServletException;

09  import javax.servlet.ServletOutputStream;

10  import javax.servlet.ServletRequest;

11  import javax.servlet.ServletResponse;

12  import javax.servlet.http.HttpServletRequest;

13  import javax.servlet.http.HttpServletResponse;

14  importcom.sun.xml.internal.ws.util.ByteArrayBuffer;

15  public class TextModifierFilter implementsFilter, ServletResponse {

16      private FilterConfigfilterConfig;

17      private String searchStr;

18      private String replaceStr;

19      public void init(FilterConfigconfig) throws ServletException {

20         this.filterConfig = config;

21      //初始化要查找的字符串和替换后的字符串的值

22         this.searchStr = "search";

23         this.replaceStr = "replace";

24      }

25      public voiddoFilter(ServletRequest request, ServletResponse response,FilterChain chain)throws IOException, ServletException {

26         HttpServletRequest hsr = (HttpServletRequest)request;

27          finalHttpServletResponse resp = (HttpServletResponse)response;

28          finalByteArrayBuffer pw = new ByteArrayBuffer();

29  //构造响应包装类

30         TextModifierFilter tmrw = new TextModifierFilter();

31     filterConfig.getServletContext().log("TextModifierFilter:Before callchain.doFilter");

32  //将请求转发给Servlet,并获取响应

33         chain.doFilter(request,tmrw);

34  //下面的代码检查响应并对需要替换的字符进行替换

35  //将响应转化为byte数组

36          byte[]bytes = pw.toByteArray();

37          if (bytes== null || (bytes.length == 0)) {

38         filterConfig.getServletContext().log("No content!");

39          }

40  //将其转换为字符串便于查找

41          Stringcontent  = new String(bytes);

42          Stringsearchcontent = (new String(bytes)).toLowerCase();

43  //查找指定字符出现的第一个位置

44          int endPos= searchcontent.indexOf(this.searchStr);

45          StringreturnStr;

46  //响应中包含这样一个字符串

47         if(endPos!=-1){

48             String front_part_Str = content.substring(0,endPos);

49            returnStr=front_part_Str + "<font color=red>"+this.replaceStr+"</font>"+content.substring(endPos + this.searchStr.length());

50          }else{

51  //响应中不包含这样一个字符串

52             returnStr = content;

53          }

54         resp.setContentLength(returnStr.length());

55         resp.getOutputStream().write(returnStr.getBytes());

56     filterConfig.getServletContext().log("TextModifierFilter:After callchain.doFilter");

57      }

58      public void destroy() {

59         this.filterConfig = null;

60      }

61      public FilterConfiggetFilterConfig() {

62          returnnull;

63      }

64      public voidsetFilterConfig(FilterConfig config) {

65      }

66      public void flushBuffer()throws IOException {

67      }

68      public int getBufferSize() {

69          return 0;

70      }

71      public StringgetCharacterEncoding() {

72          returnnull;

73      }

74      public StringgetContentType() {

75          returnnull;

76      }

77      public Locale getLocale() {

78          returnnull;

79      }

80      public ServletOutputStreamgetOutputStream() throws IOException {

81          returnnull;

82      }

83      public PrintWritergetWriter() throws IOException {

84          returnnull;

85      }

86      public boolean isCommitted(){

87          returnfalse;

88      }

89      public void reset() {

90      }

91      public void resetBuffer() {

92      }

93      public void setBufferSize(intarg0) {

94      }

95      public voidsetCharacterEncoding(String arg0) {

96      }

97      public voidsetContentLength(int arg0) {

98      }

99      public voidsetContentType(String arg0) {

100     }

101     public void setLocale(Locale arg0){

102     }

103 }

【深入学习】上述代码的主要功能集中在第25行中的doFilter()方法中,在这个方法中构造了一个响应包装器。当调用chain.doFilter(request,tmrw)方法时,Servlet的响应都已经在响应包装器对象tmrw中了,之后即可调用相关的方法获取响应的内容,并进行适当的处理。

14.4.3  编写JSP和Servlet文件

前面已经开发完成了一个完整的文本过滤器的程序,这里将接着开发演示过滤器工作过程的JSP和Servlet文件。

】实现一个过滤器的程序,查看它的工作过程。首先来看利用JSP文件实现的代码。

程序textModifier.jsp

01  <%@ page language="java"pageEncoding="GB2312"%>

02  <html>

03      <head>

04         <title>User Message</title>

05          <styletype="text/css">

06  <!--

07  .unnamed1 {

08      border: 2px solid;

09  }

10  -->

11  </style>

12      </head>

13      <bodybgcolor="#FFFFFF">

14          <formmethod="get" action="textModifier">

15             <table width="580" border="0"align="center">

16                 <thead align="center">

17                     <fontstyle="font-size:24px; color:#FF0000;">User Message</font>

18                 </thead>

19                 <tr>

20                     <tdcolspan="2"></td>

21                 </tr>

22                 <tr>

23                     <tdclass="unnamed1">

24                        UserName

25                     </td>

26                     <tdclass="unnamed1">

27                        <input type=text name=username></input>

28                     </td>

29                 </tr>

30                 <tr>

31                     <tdclass="unnamed1">

32                        Message:

33                     </td>

34                     <tdclass="unnamed1">

35                        <textarea name="content" cols="40"rows="5"></textarea>

36                     </td>

37                 </tr>

38                 <tr>

39                     <tdclass="unnamed1" align="center">

40                        <input type=submit value="submit"></input>

41                     </td>

42                     <tdclass="unnamed1" align="center">

43                        <input type="reset" value="reset">

44                     </td>

45                 </tr>

46             </table>

47         </form>

48      </body>

49  </html>

下面是用户提交输入留言信息的响应Servlet,其代码如下:

TextModiferServlet.java

01  package cn.ac.ict;

02  import java.io.IOException;

03  import javax.servlet.ServletException;

04  import javax.servlet.ServletOutputStream;

05  import javax.servlet.http.HttpServlet;

06  import javax.servlet.http.HttpServletRequest;

07  import javax.servlet.http.HttpServletResponse;

08  public class TextModiferServlet extendsHttpServlet {

09     protected void doGet(HttpServletRequest request,HttpServletResponse response) throwsServletException, IOException {

10          //设置响应的类型

11         response.setContentType("text/html;charset=gb2312");

12         ServletOutputStream out = response.getOutputStream();

13          //获取请求参数

14          Stringuser = request.getParameter("username");

15          Stringcontent = request.getParameter("content");

16          Stringoutstr = " ";

17          if (user!= null) {

18             user = new String(user.getBytes("ISO8859-1"),"GB2312");

19          }

20          if(content != null) {

21             content = newString(content.getBytes("ISO8859-1"), "GB2312");

22          }

23          if ((user!= null) && (content != null)) {

24             outstr = "User[" + user + "] say: '" +content + "'";

25          }

26          out.println("\r\n");

27          out

28                 .println("<!DOCTYPE HTML PUBLIC\"-//w3c//dtdhtml 4.0 transitional//en\">\r\n");

29         out.println("<html>\r\n");

30         out.println("<head>\r\n");

31         out.println("<title>User Message</title>\r\n");

32         out.println("<style type=\"text/css\">\r\n");

33         out.println("<!--\r\n");

34         out.println(".unnamed1 {\r\n");

35         out.println("\tborder: 2px solid;\r\n");

36         out.println("}\r\n");

37          out.println("-->\r\n");

38         out.println("</style>\r\n");

39         out.println("</head>\r\n");

40         out.println("<body bgcolor=\"#FFFFFF\">\r\n");

41         out.println("<form method=\"get\" action=\"textModifier\">\r\n");

42          out.println("<tablewidth=\"580\" border=\"0\"align=\"center\">\r\n");

43         out.println("<thead align=\"center\"><font style=\"font-size:24px;color:#FF0000;\">User Message</font></thead>\r\n");

44         out.println("<tr><td colspan=\"2\">" + outstr +"</td></tr>\r\n");

45         out.println("<tr>\r\n");

46         out.println("<tdclass=\"unnamed1\">UserName</td>\r\n");

47         out.println("<td class=\"unnamed1\"><input type=textname = username></input></td>\r\n");

48         out.println("</tr>\r\n");

49         out.println("<tr>\r\n");

50         out.println("<td class=\"unnamed1\">Message:</td>\r\n");

51         out.println("<td class=\"unnamed1\"><textarea name=\"content\"cols=\"40\"rows=\"5\"></textarea></td>\r\n");

52          out.println("</tr>\r\n");

53         out.println("<tr>\r\n");

54         out.println("<td class=\"unnamed1\"align=\"center\"><input type=submitvalue=\"submit\"></input> </td>\r\n");

55         out.println("<td class=\"unnamed1\"align=\"center\"><input type=\"reset\"value=\"reset\"> </td> \r\n");

56         out.println("</tr>\r\n");

57         out.println("</table>\r\n");

58         out.println("\r\n");

59         out.println("\r\n");

60         out.println("\r\n");

61         out.println("\r\n");

62         out.println("</form>\r\n");

63         out.println("\r\n");

64         out.println("\r\n");

65         out.println("</body>\r\n");

66         out.println("</html>");

67      }

68     protected void doPost(HttpServletRequest request,HttpServletResponse response)throwsServletException, IOException {

69         doGet(request, response);

70      }

71  }

【运行程序】准备好所有需要使用的文件后,可以按照如下步骤发布这个Web应用。

(1)编译输出流管理类、响应包装器和过滤器的Java程序。编译时需要将servlet-api.jar放到类路径中,编译完成后,将得到的字节码文件复制到Web应用的WEB-INF\classes目录下,存放位置与包的结构一致。

(2)在Web应用的web.xml文件中配置使用的Servlet和Servlet过滤器,也就是在web.xml文件中添加如下代码:

01  <!-- 配置Servlet  -- >

02    <servlet>                                         

03       <servlet-name>textModifier</servlet-name>          

04    <servlet-class>cn.ac.ict.Servlet.TextModiferServlet</servlet-class>

05     </servlet>                                        

06     <servlet-mapping>                                 

07          <servlet-name>textModifier</servlet-name>      

08           <url-pattern>/textModifier</url-pattern>          

09     </servlet-mapping>  

10  <!-- 配置Servlet过滤器  -- >

11         <filter>

12             <filter-name>Text Content Modifier</filter-name>

13     <filter-class>cn.ac.ict.Filter.TextModifierFilter</filter-class>

14         </filter>

15         <filter-mapping>

16             <filter-name>Text Content Modifier</filter-name>

17             <url-pattern>/textModifier</url-pattern>

18         </filter-mapping>   

(3)启动Tomcat或者重新加载Web应用,在浏览器地址栏中输入http://localhost:8080/14/textModifier.jsp,并填写内容,显示页面如图14.2所示。

(4)可以看到用户的留言中包含了字符串search,提交后可以看到页面显示如

【深入学习】在这个Servlet中,根据用户的留言信息构造一个消息再反馈给用户,而且保留了用户输入的各个组件,并通过JSP文件显示用户界面。

 

   图14.2  用户输入界面    

 

                         图14.3  过滤效果

14.5  Servlet监听器简介

Servlet监听器是在Servlet 2.3版中引入的技术,它可以监听客户端的请求、服务端的操作等。Servlet监听器的很多特性与Servlet过滤器是一致的,它的很多概念也与Java中监听器的概念一致。Servlet监听器可以在特定事件发生时进行监听,并根据其作出相应的反应。

Servlet监听器的内容相对比较容易理解,下面将介绍Servlet监听器的常用类和接口,并通过例子讲述如何使用Servlet监听器。

14.5.1  监听服务器ServletContext对象

对ServletContext对象进行监听的接口有ServletContextAttributeListener和ServletContextListener,可以分别用于监听ServletContext对象中属性的变化和ServletContext对象本身的变化。

1.ServletContextAttributeListener接口

实现ServletContextAttributeListener接口的监听器可以监听到ServletContext对象中属性的变化,其提供的方法有:

  ● voidattributeAdded(ServletContextAttributeEvent scab)。

  ● void attributeRemoved(ServletContextAttributeEventscab)。

  ● voidattributeReplaced(ServletContextAttributeEvent scab)。

实现ServletContextAttributeListener接口可以监听对ServletContext属性的操作,当增加、删除、修改操作时,都会调用相应的方法。

  ● 当在ServletContext增加一个属性时,激发attributeAdded(ServletContextAttributeEvent scab)方法。

  ● 当在ServletContext删除一个属性时,激发attributeRemoved(ServletContextAttributeEvent scab)方法。

  ● 当在ServletContext属性被重新设置时,激发attributeReplaced(ServletContextAttributeEvent scab)方法。

2.ServletContextListener接口

实现ServletContextListener接口的监听器可以监听ServletContext对象本身的变化,其提供的方法有:

  ● void contextDestroyed(ServletContextEventsce)。

  ● void contextInitialized(ServletContextEventsce)。

实现ServletContextListener接口可以监听ServletContext的操作。

  ● 当创建ServletContext时,激发contextInitialized(ServletContextEvent sce)方法。

  ● 当销毁ServletContext时,激发contextDestroyed(ServletContextEvent sce)方法。

14.5.2  监听客户会话

对客户会话进行监听的接口有HttpSessionAttributeListener接口、HttpSessionListener接口、HttpSessionActivationListener接口和HttpSessionBindingListener接口,可以分别用于监听HttpSession对象中属性的变化和HttpSession对象本身状态的变化。

1.HttpSessionAttributeListener接口

实现HttpSessionAttributeListener接口的监听器可以监听到HttpSession对象中属性的变化,其提供的方法有:

  ● void attributeAdded(HttpSessionBindingEventse)。

  ● voidattributeRemoved(HttpSessionBindingEvent se)。

  ● voidattributeReplaced(HttpSessionBindingEvent se)。

实现HttpSessionAttributeListener接口可以监听HttpSession中属性的操作。

  ● 当在Session增加一个属性时,激发attributeAdded(HttpSessionBindingEvent se)方法。

  ● 当在Session删除一个属性时,激发attributeRemoved(HttpSessionBindingEvent se)方法。

  ● 当在Session属性被重新设置时,激发attributeReplaced(HttpSessionBindingEvent se)方法。

2.HttpSessionListener接口

实现HttpSessionListener接口的监听器可以监听HttpSession对象本身的创建和销毁,其提供的方法有:

  ● void sessionCreated(HttpSessionEvent se)。

  ● void sessionDestroyed(HttpSessionEvent se)。

实现HttpSessionListener接口的监听器可以监听HttpSession的操作。

  ● 当创建一个Session时,激发sessionCreated(SessionEvent se)方法。

  ● 当销毁一个Session时,激发sessionDestroyed (HttpSessionEvent se)方法。

3.HttpSessionActivationListener接口

用于监听HttpSession对象的状态,其提供的方法有:

  ● void sessionDidActivate(HttpSessionEventse)。

  ● void sessionWillPassivate(HttpSessionEventse)。

4.HttpSessionBindingListener接口

实现该接口,可以监听HttpSession对象是被激活还是钝化。

  ● 当激活一个HttpSession对象时,激发sessionDidActivate(HttpSessionEvent se)方法。

  ● 当钝化一个HttpSession对象时,激发sessionWillPassivate (HttpSessionEvent se)方法。

14.5.3  监听客户请求

对ServletRequest对象进行监听的接口有ServletRequestAttributeListener和ServletRequestListener,这个是Servlet 2.4版本的新增监听器,它们分别用于监听ServletRequest对象中属性的变化和ServletRequest对象本身的变化。

1.ServletRequestAttributeListener接口

实现ServletRequestAttributeListener接口的监听器可以监听到ServletRequest对象中属性的变化,其提供的方法有:

  ● void attributeAdded(ServletRequestAttributeEventscab)。

  ● voidattributeRemoved(ServletRequestAttributeEvent scab)。

  ● voidattributeReplaced(ServletRequestAttributeEvent scab)。

说明:实现ServletRequestAttributeListener接口可以监听对ServletRequest属性的操作,当增加、删除、修改操作时,都会调用相应的方法。

  ● 当在ServletRequest增加一个属性时,激发attributeAdded(ServletRequestAttributeEvent scab)方法。

  ● 当在ServletRequest删除一个属性时,激发attributeRemoved(ServletRequestAttributeEvent scab)方法。

  ● 当在ServletRequest属性被重新设置时,激发attributeReplaced(ServletRequestAttributeEvent scab)方法。

2.ServletRequestListener接口

实现ServletRequestListener接口的监听器可以监听ServletRequest对象本身的变化,其提供的方法有:

  ● void requestDestroyed(ServletRequestEventsce)。

  ● void requestInitialized(ServletRequestEventsce)。

实现ServletRequestListener接口可以监听ServletRequest的操作。

  ● 当创建ServletRequest时,激发requestInitialized(ServletRequestEvent sce)方法。

  ● 当销毁ServletRequest时,激发requestDestroyed(ServletRequestEvent sce)方法。

14.6  小    结

Servlet监听器和过滤器是Servlet 2.3后新增加的一个重要特性,在许多应用中体现了很大的优势。本章介绍了Servlet监听器和过滤器的工作原理和使用方法,希望读者多多练习,以便更好地理解它们的工作原理。

Servlet过滤器主要运用了两个包装类,即ServletRequest和ServletResponse,通过它们来实现具体的过滤功能。Servlet监听器主要是监听接口,然后通过接口找到需要监听的程序。