Listener
Listener是Servlet的监听器,它可以监听客户端的请求、服务端的操作等。通过监听器,可以自动激发一些操作,比如监听在线的用户的数量。当增加一个HttpSession时,就激发sessionCreated(HttpSessionEvent se)方法,这样就可以给在线人数加1。Javax.servlet中定义了三类监听器:ServletContex相关、ServletRequest相关、和HttpSession相关的监听器。
ServletContext相关监听器:
ServletContextAttributeListener监听对ServletContext属性的操作,比如增加、删除、修改属性。
void attributeAdded(ServletContextAttributeEvent scab):在servlet上下文增加了一个属性时触发;
void attributeRemoved(ServletContextAttributeEvent scab):在servlet上下文移除一个已存在的属性时触发;
void attributeReplaced(ServletContextAttributeEvent scab):在servlet上下文替换一个已存在的属性时触发。
ServletContextListener监听ServletContext。接收到web应用中servlet上下文载入或销毁的事件通知。
当创建ServletContext时,激发contextInitialized(ServletContextEvent sce)方法;所有的ServletContextListener都将先于filter和servlet的初始化前被通知。
当销毁ServletContext时,激发contextDestroyed(ServletContextEvent sce)方法。所有的filter和servlet都将在ServletContextListener被通知前被destory。
事实上,contextListener、filter、servlet的初始化顺序依次是listener、filter、servlet。
ServletRequest相关监听器
ServletRequestListener:当你希望接收到各种request请求进入(coming in)或离开(out of)一个web部件(component)的消息时,你可以通过实现这个接口来完成。当一个request开始进入每一个web应用的第一个servlet或filter时,将触发进入(coming in)web应用事件,当一个request离开最后一个servlet或filter链的第一个filter时,将触发一个离开(out of)web应用事件。(注意filter链的执行顺序)
该监听器定义了下面两个方法:
void requestDestroyed(ServletRequestEvent sre): request将离开一个web应用;
void requestInitialized(ServletRequestEvent sre) :request 将进入一个web应用。
ServletRequestAttributeListener:当你希望接收到request的属性变更事件时,可以通过实现这个接口来完成。变更通知只在request处于web应用中的时候发出。Request处于一个web应用指的是,从一个request进入(coming in)web应用到离开(out of)web应用之间的时间。
该监听器定义了下面方法:
void attributeAdded(ServletRequestAttributeEvent srae): 向一个request里面增加一个属性时触发;
void attributeRemoved(ServletRequestAttributeEvent srae): 从一个request里面移除一个属性时触发;
void attributeReplaced(ServletRequestAttributeEvent srae): 从一个request里面替换一个属性时触发。
HttpSession相关监听器:
HttpSessionListener监听HttpSession的操作。
当创建一个Session时,激发session Created(HttpSessionEvent se)方法;
当销毁一个Session时,激发sessionDestroyed(HttpSessionEvent se)方法。
HttpSessionAttributeListener监听HttpSession中的属性的操作。
当在Session增加一个属性时,激发attributeAdded(HttpSessionBindingEvent se) 方法;
当在Session删除一个属性时,激发attributeRemoved(HttpSessionBindingEvent se)方法;
当在Session属性被重新设置时,激发attributeReplaced(HttpSessionBindingEvent se) 方法。
如何指定应用事件监听程序
应用事件监听器程序是建立或修改servlet环境或会话对象时通知的类。它们是servlet规范的版本2.3中的新内容。这里只简单地说明用来向Web应用注册一个监听程序的web.xml的用法。
注册一个监听程序涉及在web.xml的web-app元素内放置一个listener元素。在listener元素内,listener-class元素列出监听程序的完整的限定类名,如下所示:
package.ListenerClass
虽然listener元素的结构很简单,但请不要忘记,必须正确地给出web-app元素内的子元素的次序。
*******************
listener元素位于所有的servlet 元素之前以及所有filter-mapping元素之后。此外,因为应用生存期监听程序是serlvet规范的2.3版本中的新内容,所以必须使用 web.xml DTD的2.3版本,而不是2.2版本。
*******************
例如,程序清单5-20给出一个名为ContextReporter的简单的监听程序,它实现了ServletContextListener接口,只要Web应用的Servlet-Context建立(如装载Web应用)或消除(如服务器关闭)时,它就在标准输出上显示一条消息。程序清单5-21给出此监听程序注册所需要的web.xml文件的一部分。
程序清单5-20 ContextReporterjava
package moreservlets;
import javax.servlet.*;
import java.util.*;
public class ContextReporter implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
//ServletContextEvent的实例的getServletContext()方法返回SevletContext对象
ServletContext servletContext = event.getServletContext();
System.out.println("Context created on " +
new Date() + ".");
}
public void contextDestroyed(ServletContextEvent event) {
System.out.println("Context destroyed on " +
new Date() + ".");
}
}
程序清单5-21 web.xml(声明一个监听程序的摘录)
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
…
package.ListenerClass
...
Filter
Servlet过滤器是小型的Web组建,它可以拦截请求和响应,以便查看,提取或以某种方式操作正在客户机和服务器之间交换的数据。我们可以用过滤器解决中文编码问题。它先于与之相关的servlet或jsp页面运行在服务器上,过滤器可以附加到一个或多个servlet或jsp页面上,并且可以检查进入这些资源的请求信息。过滤器可以做如下选择:
以常规的方式调用资源(即调用servlet或jsp页面)
利用修改过的请求信息调用资源。
调用资源,但在发送响应道客户机前对其进行修改。
组织该资源调用,代之以转到其他的资源。
过滤器通过Web部署描述文件web.xml中的XML元素来声明,这样允许添加和删除过滤器,而无需改动任何应用程序代码或JSP页面。
过滤器首先是根据url-pattern来判断是用哪个过滤器,
如果url-pattern符合多个过滤器的时候,就根据过滤器在web.xml中配置的先后顺序来依次执行过滤器。
如何实现Filter
要想开发一个过滤器,就必须实现javax.servlet.Filter接口,在Filter接口中定义了init,doFilter,destroy方法。下面是一个过滤器走过的流程:
init(FilterConfig filterConfig)
这个方法由Web容器在过滤器实例化之后被调用。用于执行本过滤器的初始化操作,通过参数FilterConfig可以得到这个过滤器的所有配置的参数。它只在此过滤器第一次初始化时执行,不是每次调用过滤器都执行它。FilterConfig对象具有一个getInitParameter方法,它能够访问部署描述符文件(web.xml)中分配的过滤器初始化参数。
doFilter(ServletRequest request,ServletResponse response,FilterChain chain)
在该方法放入过滤行为,由链路终端用户请求,Web容器将会在每个request/reponse链路中调用doFilter()方法。通过传递FilterChain对象,doFilter()方法可以将request和reponse对象传递到链路中的下一个实体,就是说doFilter()方法就是具体的过滤处理代码,同时它可以决定被浏览器处理后下一步要进行的操作。
DoFilter的最后一个参数为FilterChain对象,对此对象调用对象的doFilter方法以激活下一个相关的过滤器。如果没有另一个过滤器与servlet或jsp页面关联,则servlet或jsp页面被激活。
destroy(),这个方法由Web容器负责调用。通常在销毁Filter对象的实例之前调用destory()方法,因为它是和init()方法相对应,所以这个方法主要用户释放init()中申请的资源。
Filter在web.xml中配置和部署
Filter的配置和部署工作是在Web应用的web.xml配置文件中进行的。在Filter的配置中应用到两个配置元素:
...
filter元素向系统注册一个过滤对象,它包含的子元素有:
filter-name用于定义Filter的名称。
Filter-class用于定义这个Filter的具体实现对象。
init-param 这是一个可选的元素,它定义可利用FilterConfig的getInitParameter方法读取的初始化参数。单个过滤器元素可包含多个init-param元素。
...
filter-mapping元素指定该过滤对象所应用的URL。它包含的子元素有:
其中filter-name用于引用在filter元素中定义的filter名称。
url-pattern 此元素声明一个以斜杠(/)开始的模式,用于指明与URL相匹配的方式,只有相匹配的请求才会被Filter所处理。/*表示处理所有的请求,/*.jsp表示处理所有jsp页面的请求。/manage/*表示对/manage下的所有请求。如果希望过滤器适用于多个模式,可重复整个filter-mapping元素。
servlet-name 此元素给出一个名称,此名称必须与利用servlet元素给予servlet或JSP页面的名称相匹配。不能给单个filter-mapping元素提供多个servlet-name元素项。如果希望过滤器适合于多个servlet名,可重复这个filter-mapping元素。
例如: 字符编码过滤器
SimpleFilter
com.darkmi.filter.SimpleFilter
encoding
UTF-8
SimpleFilter
/*
package cn.hxex.tutorial;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.UnavailableException;
public class SetCharacterEncodingFilter implements Filter {
protected String encoding = null;
protected FilterConfig filterConfig = null;
protected boolean ignore = true;
public void destroy() {
this.encoding = null;
this.filterConfig = null;
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// Conditionally select and set the character encoding to be used
if (ignore || (request.getCharacterEncoding() == null)) {
String encoding = selectEncoding(request);
if (encoding != null)
//设置对客户端请求进行重新编码的编码,
request.setCharacterEncoding(encoding);
}
// Pass control on to the next filter
chain.doFilter(request, response);
}
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
this.encoding = filterConfig.getInitParameter("encoding");
String value = filterConfig.getInitParameter("ignore");
if (value == null)
this.ignore = true;
else if (value.equalsIgnoreCase("true"))
this.ignore = true;
else if (value.equalsIgnoreCase("yes"))
this.ignore = true;
else
this.ignore = false;
}
// ------------------------------------------------------
//Protected Methods
protected String selectEncoding(ServletRequest request) {
return (this.encoding);
}
}
使浏览器不缓存页面的过滤器:
import javax.servlet. * ;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 用于的使 Browser 不缓存页面的过滤器
*/
public class ForceNoCacheFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException
{
((HttpServletResponse) response).setHeader( " Cache-Control " , " no-cache " );
((HttpServletResponse) response).setHeader( " Pragma " , " no-cache " );
((HttpServletResponse) response).setDateHeader ( " Expires " , - 1 );
filterChain.doFilter(request, response);
}
public void destroy() {
}
public void init(FilterConfig filterConfig) throws ServletException {
}
}