Servlet程序由Servlet,Filter和Listener组成,其中监听器用来监听Servlet容器上下文。
监听器通常分三类:基于Servlet上下文的ServletContex监听,基于会话的HttpSession监听和基于请求的ServletRequest监听。
?
- ServletContex监听器
ServletContex又叫application,存在范围是整个Servlet容器生命周期,当系统启动时就会创建,系统关闭时会销毁,该对象通常存放一些非常通用的数据,但是不推荐存放太多,否则长期占据内存空间会影响服务器性能。
基于ServletContex的监听器可以继承两个接口并实现接口中相应的方法:
ServletContextListener接口定义了两个方法contextInitialized和contextDestroyed,分别在ServletContex创建和销毁时触发;
ServletContextAttributeListener接口定义了三个方法attributeAdded,attributeRemoved和attributeReplaced,分别在给ServletContex添加属性值,删除属性值和替换属性值时触发。
下面创建了一个基于Application的监听器:
- ?/**?
- ?*?Application监听器,Servlet中的Application即ServletContext?
- ?*?@author?Administrator?
- ?*/??
- public?class?ApplicationListener?implements?ServletContextListener,??
- ????????ServletContextAttributeListener?{??
- ??????
- ????/**?
- ?????*?application销毁时触发的事件?
- ?????*/??
- ????@Override??
- ????public?void?contextDestroyed(ServletContextEvent?arg0)?{??
- ????????System.out.println("Application销毁:"+arg0.getServletContext());??
- ????}??
- ??????
- ????/**?
- ?????*?application初始化时触发的方法?
- ?????*/??
- ????@Override??
- ????public?void?contextInitialized(ServletContextEvent?arg0)?{??
- ????????System.out.println("Application创建:"+arg0.getServletContext());??
- ????}??
- ??????
- ????/**?
- ?????*?application中添加属性值时触发的方法?
- ?????*/??
- ????@Override??
- ????public?void?attributeAdded(ServletContextAttributeEvent?arg0)?{??
- ????????System.out.println("Application添加新属性:key="+arg0.getName()+"??value="+arg0.getValue());??
- ????}??
- ??????
- ????/**?
- ?????*?application中删除属性值时触发的方法?
- ?????*/??
- ????@Override??
- ????public?void?attributeRemoved(ServletContextAttributeEvent?arg0)?{??
- ????????System.out.println("Application移除属性:key="+arg0.getName()+"??value="+arg0.getValue());??
- ????}??
- ??????
- ????/**?
- ?????*?application中替换属性值时触发的方法?
- ?????*/??
- ????@Override??
- ????public?void?attributeReplaced(ServletContextAttributeEvent?arg0)?{??
- ????????System.out.println("Application替换属性:key="+arg0.getName()+"??value="+arg0.getValue());??
- ????}??
- ??
- }??
?
最后在web.xml需要注册监听器,注册方式非常简单,注意标签<description>和<display-name>不是必须的:
?
- <listener>??
- ????<description>application?listener</description>??
- ????<display-name>application_listener</display-name>??
- ????<listener-class>com.bless.listener.application.ApplicationListener</listener-class>??
- </listener>??
随后启动java web项目,监听器就会运行。
?
?
?
- Session监听器
Session对于做web项目的人来说应该非常熟悉了,Session的生命周期是一个用户的一次会话,简单的说当一个用户进入某个网站,在该网站服务器就已经为用户创建了一个Session对象,用户在网站内的任何操作都是在session周期内。
误区:某些人认为我进入某网站,随后关闭浏览器,我的session就已经销毁了。其实不然,因为session存储在服务器端,服务器并不能主动捕获到浏览器关闭的事件,即使关闭浏览器,Session对象依然存在服务器中。所以如果编写web应用时一定要考虑session什么时候销毁,销毁session对象的方式有两种:一种是调用session的invalidate方法,另一种是在web.xml中定义session失效时间session-timeout。
Session监听器也有两个接口,其功能与前面介绍的ServletContex类似:HttpSessionListener用于监听Session创建和销毁的事件,HttpSessionAttributeListener用于监听Session属性赋值,删除和替换的事件:
- /**?
- ?*?Session监听器?
- ?*?@author?Administrator?
- ?*/??
- public?class?SessionListener?implements?HttpSessionListener,??
- ????????HttpSessionAttributeListener?{??
- ????Vector<HttpSession>?listSession?=?null;??
- ??????
- ????/**?
- ?????*?创建Session调用的方法?
- ?????*?将session对象放入listSession集合中?
- ?????*/??
- ????@Override??
- ????public?void?sessionCreated(HttpSessionEvent?arg0)?{??
- ????????synchronized?(this)?{??
- ????????????if(listSession?==?null){??
- ????????????????listSession?=?new?Vector<HttpSession>();??
- ????????????}??
- ????????}??
- ????????listSession.add(arg0.getSession());??
- ????????System.out.println("\n\n创建一个Session:"+arg0.getSession());??
- ????????System.out.println("[当前存在的Session:]");??
- ????????for?(HttpSession?session?:?listSession)?{??
- ????????????System.out.println("--->"+session);??
- ????????}??
- ????}??
- ??????
- ????/**?
- ?????*?销毁Session调用的方法?
- ?????*?移除listSession集合对应session值?
- ?????*/??
- ????@Override??
- ????public?void?sessionDestroyed(HttpSessionEvent?arg0)?{??
- ????????listSession.remove(arg0.getSession());??
- ????????System.out.println("\n\n销毁一个Session:"+arg0.getSession());??
- ????????System.out.println("[当前存在的Session:]");??
- ????????for?(HttpSession?session?:?listSession)?{??
- ????????????System.out.println("--->"+session);??
- ????????}??
- ????}??
- ??????
- ????/**?
- ?????*?session属性添加时调用的方法?
- ?????*/??
- ????@Override??
- ????public?void?attributeAdded(HttpSessionBindingEvent?arg0)?{??
- ????????System.out.println("\n\n添加一条Session-->key:"+arg0.getName()+"????属性value:"+arg0.getValue());??
- ????}??
- ??????
- ????/**?
- ?????*?session属性移除时调用的方法?
- ?????*/??
- ????@Override??
- ????public?void?attributeRemoved(HttpSessionBindingEvent?arg0)?{??
- ????????System.out.println("\n\n删除一条Session-->key:"+arg0.getName()+"????属性value:"+arg0.getValue());??
- ????}??
- ??????
- ????/**?
- ?????*?session属性替代时调用的方法?
- ?????*/??
- ????@Override??
- ????public?void?attributeReplaced(HttpSessionBindingEvent?arg0)?{??
- ????????System.out.println("\n\n覆盖一条Session-->key:"+arg0.getName()+"????属性value:"+arg0.getValue());??
- ????}??
- ??
- }??
?
在web.xml中定义相应监听器配置:
?
- <listener>??
- ????<listener-class>com.bless.listener.session.SessionListener</listener-class>??
- ??</listener>??
- <!--?Session超时配置?-->??
- ??<session-config>??
- ????<session-timeout>1</session-timeout>??
- ??</session-config>??
?
?
?
?
- Request监听器
request监听器使用方法跟前面也是非常类似的,一个request生命周期是向服务器发送请求到服务器响应最后反应到页面的整个过程。Request监听器对应ServletRequestListener,ServletRequestAttributeListener接口,根据不同需求实现相应接口就行了。
- /**?
- ?*?Request事件监听器?
- ?*?@author?Administrator?
- ?*/??
- public?class?RequestListener?implements?ServletRequestListener,??
- ????????ServletRequestAttributeListener?{??
- ??
- ????@Override??
- ????public?void?requestDestroyed(ServletRequestEvent?arg0)?{??
- ????????System.out.println("request销毁:"+arg0.getServletRequest());??
- ????}??
- ??
- ????@Override??
- ????public?void?requestInitialized(ServletRequestEvent?arg0)?{??
- ????????System.out.println("request创建:"+arg0.getServletRequest());??
- ????}??
- ??
- ????@Override??
- ????public?void?attributeAdded(ServletRequestAttributeEvent?arg0)?{??
- ????????System.out.println("request属性添加???key="+arg0.getName()+"???value="+arg0.getValue());??
- ????}??
- ??
- ????@Override??
- ????public?void?attributeRemoved(ServletRequestAttributeEvent?arg0)?{??
- ????????System.out.println("request属性删除???key="+arg0.getName()+"???value="+arg0.getValue());??
- ????}??
- ??
- ????@Override??
- ????public?void?attributeReplaced(ServletRequestAttributeEvent?arg0)?{??
- ????????System.out.println("request属性替换???key="+arg0.getName()+"???value="+arg0.getValue());??
- ????}??
- ??
- }??
? web.xml配置:
- <listener>??
- ????<listener-class>com.bless.listener.request.RequestListener</listener-class>??
- ??</listener>??
?
- Filter过滤器
当页面发送请求时,符合filter过滤范围的请求会首先进入过滤器,过滤器就可以执行一些过滤操作:比如编码格式,session验证,日志记录等。而这些功能都是自己编写过滤器实现的。
要实现一个过滤器,需要继承Filter接口,实现init、doFilter和destroy方法,这三个方法分别在过滤器初始化、过滤器运行和过滤器销毁时执行。
下面这段代码,是一个字符集过滤器,每次请求都会设置字符集编码格式,注意每次请求都会运行doFilter方法,过滤之后你需要在方法内调用FilterChain.doFilter这样就能让请求访问指定的servlet。
假设你不希望请求访问下一个servlet,你可以选择重定向,跳转到指定页面。
- /**?
- ?*??
- ?*?@author?????:?bless<505629625@qq.com>?
- ?*?Create?Time?:?2011-5-10下午10:38:19?
- ?*?Description?:?字符集格式过滤器?
- ?*?
- ?*/??
- public?class?EncodingFilter?implements?Filter?{??
- ????//默认编码格式UTF-8??
- ????private?static?final?String?DEFAULT_ENCODE?=?"UTF-8";??
- ??????
- ????private?String?encodeName;?//?编码格式??
- ??
- ????public?void?destroy()?{??
- ??
- ????}??
- ??
- ????/**?
- ?????*?@see?Filter#doFilter(ServletRequest,?ServletResponse,?FilterChain)?
- ?????*/??
- ????public?void?doFilter(ServletRequest?request,?ServletResponse?response,??
- ????????????FilterChain?chain)?throws?IOException,?ServletException?{??
- ????????try?{??
- ????????????if?(encodeName?==?null?||?"".equals(encodeName.trim()))?{??
- ????????????????request.setCharacterEncoding(DEFAULT_ENCODE);??
- ????????????????response.setCharacterEncoding(DEFAULT_ENCODE);??
- ????????????}?else?{??
- ????????????????request.setCharacterEncoding(encodeName);??
- ????????????}??
- ????????}?catch?(UnsupportedEncodingException?e)?{??
- ????????????throw?new?UnsupportedEncodingException("编码格式过滤错误,请确认web.xml填入了正确的编码格式");??
- ????????}??
- ????????chain.doFilter(request,?response);??
- ????}??
- ??
- ????/**?
- ?????*?@see?Filter#init(FilterConfig)?
- ?????*/??
- ????public?void?init(FilterConfig?fConfig)?throws?ServletException?{??
- ????????//获取web.xml配置的<param-name>encodeName</param-name>的值??
- ????????this.setEncodeName(fConfig.getInitParameter("encodeName"));???
- ????}??
- ??
- ????public?String?getEncodeName()?{??
- ????????return?encodeName;??
- ????}??
- ??
- ????public?void?setEncodeName(String?encodeName)?{??
- ????????this.encodeName?=?encodeName;??
- ????}??
- ??
- }??
?
然后在web.xml中定义filter即可,标签init-param可以做一个参数配置,在filter中通过init方法参数FilterConfig.getInitParameter获得:
- <filter>??
- ????<filter-name>encoding</filter-name>??
- ????<filter-class>com.mt.filter.EncodingFilter</filter-class>??
- ????<init-param>??
- ????????<param-name>encodeName</param-name>??
- ????????<param-value>GBK</param-value>??
- ????</init-param>??
- ??</filter>??
- ??<filter-mapping>??
- ????<filter-name>encoding</filter-name>??
- ????<url-pattern>/*</url-pattern>??
- ??</filter-mapping>??