Servlet过滤器是小型的 Web 组件,它们拦截请求和响应,以便查看、提取或以某种方式操作正在客户机和服务器之间交换的数据。过滤器是通常封装了一些功能的 Web 组件,这些功能虽然很重要,但是对于处理客户机请求或发送响应来说不是决定性的。典型的例子包括记录关于请求和响应的数据、处理安全协议、管理会话属性等。过滤器提供一种面向对象的模块化机制,用以将公共任务封装到可插入的组件中,这些组件通过一个配置文件来声明,并动态地处理。
Servlet过滤器中结合了许多元素,从而使得过滤器成为独特、强大和模块化的 Web 组件。Servlet过滤器具有如下特点:
1、声明式的:过滤器通过 Web 部署描述符(web.xml)中的 XML 标签来声明。这样允许添加和删除过滤器,而无需改动任何应用程序代码或 JSP 页面。
2、动态的:过滤器在运行时由 Servlet 容器调用来拦截和处理请求和响应。
3、灵活的:过滤器在 Web 处理环境中的应用很广泛,涵盖诸如日志记录和安全等许多最公共的辅助任务。过滤器还是灵活的,因为它们可用于对来自客户机的直接调用执行预处理和后期处理,以及处理在防火墙之后的 Web 组件之间调度的请求。最后,可以将过滤器链接起来以提供必需的功能。
4、模块化的:通过把应用程序处理逻辑封装到单个类文件中,过滤器从而定义了可容易地从请求/响应链中添加或删除的模块化单元。
5、可移植的:与 Java 平台的其他许多方面一样,Servlet过滤器是跨平台和跨容器可移植的,从而进一步支持了 Servler 过滤器的模块化和可重用本质。
6、可重用的:归功于过滤器实现类的模块化设计,以及声明式的过滤器配置方式,过滤器可以容易地跨越不同的项目和应用程序使用。
7、透明的:在请求/响应链中包括过滤器,这种设计是为了补充(而不是以任何方式替代)servlet 或 JSP 页面提供的核心处理。因而,过滤器可以根据需要添加或删除,而不会破坏 servlet 或 JSP 页面。
所以 Servlet过滤器是通过一个配置文件来灵活声明的模块化可重用组件。过滤器动态地处理传入的请求和传出的响应,并且无需修改应用程序代码就可以透明地添加或删除它们。最后,过滤器独立于任何平台或者 Servlet 容器,从而允许将它们容易地部署到任何相容的 J2EE 环境中。
二 Servlet 过滤器体系结构
正如其名称所暗示的,Servlet过滤器用于拦截传入的请求和/或传出的响应,并监视、修改或以某种方式处理正在通过的数据流。过滤器是自包含、模块化的组件,可以将它们添加到请求/响应链中,或者在无需影响应用程序中其他 Web 组件的情况下删除它们。过滤器仅只是改动请求和响应的运行时处理,因而不应该将它们直接嵌入Web应用程序框架,除非是通过 Servlet API 中良好定义的标准接口来实现。
Web 资源可以配置为没有过滤器与之关联(这是默认情况)、与单个过滤器关联(这是典型情况),甚至是与一个过滤器链相关联。那么过滤器究竟做什么呢? 像 servlet 一样,它接受请求并响应对象。然后过滤器会检查请求对象,并决定将该请求转发给链中的下一个组件,或者中止该请求并直接向客户机发回一个响应。如果请求被转发了,它将被传递给链中的下一个资源(另一个过滤器、servlet 或 JSP 页面)。在这个请求设法通过过滤器链并被服务器处理之后,一个响应将以相反的顺序通过该链发送回去。这样就给每个过滤器都提供了根据需要处理响应对象的机会。
当过滤器在 Servlet 2.3 规范中首次引入时,它们只能过滤 Web 客户机和客户机所访问的指定 Web 资源之间的内容。如果该资源然后将请求调度给其他 Web 资源,那就不能向幕后委托的任何请求应用过滤器。2.4 规范消除了这个限制。Servlet过滤器现在可以应用于 J2EE Web 环境中存在请求和响应对象的任何地方。因此,Servlet过滤器可以应用在客户机和 servlet 之间、servlet 和 servlet 或 JSP 页面之间,以及所包括的每个 JSP 页面之间。
三、步骤
经历三个步骤 :
1、编写过滤器实现类的程序
2、把该过滤器添加到Web应用程序中(通过在Web部署描述符/web.xml中声明它)
3、把过滤器与应用程序一起打包并部署它
3个接口:Filter 、FilterChain和FilterConfig。
从编程的角度看,过滤器类将实现Filter接口,然后使用FilterChain和FilterConfig接口。该过滤器类的一个引用将传递给FilterChain对象,以允许过滤器把控制权传递给链中的下一个资源。FilterConfig对象将由容器提供给过滤器,以允许访问该过滤器的初始化数据。
四、过滤器生命周期方法
1、init() :这个方法在容器实例化过滤器时被调用,它主要设计用于使过滤器为处理做准备。该方法接受一个 FilterConfig类型的对象作为输入。
2、doFilter() :与servlet拥有一个service()方法(这个方法又调用doPost()或者doGet())来处理请求一样,过滤器拥有单个用于处理请求和响应的方法---doFilter()。这个方法接受三个输入参数:一个ServletRequest 、ServletResponse和一个FilterChain对象。
3、destroy():正如想像的那样,这个方法执行任何清理操作,这些操作可能需要在自动垃圾收集之前进行。
以下是一个完成字符集转换的过滤器实例。 首先完成过滤器代码,在init方法中读取配置参数,在doFilter中完成字符集的转换。
package myproj.filter; 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; public class SetCharacterEncodingFilter implements Filter{ //定义替换后的字符集,从过滤器的配置参数中读取 String newCharSet; public void destroy(){} public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException { //处理请求字符集 request.setCharacterEncoding(newCharSet); //处理响应字符集 response.setContentType("text/html;charset="+newCharSet); //传递给下一个过滤器,如果没有filter那就是请求的资源 chain.doFilter(request,response); } public void init(FilterConfig filterConfig) throws ServletException { //从过滤器的配置中获得初始化参数,如果没有就使用默认值 if(filterConfig.getInitParamter("newcharset")!=null){ newCharSet = filterConfig.getInitParamter("newcharset"); }else{ newCharSet = "GB2312"; } } }初始化: 当容器第一次加载该过滤器时, init() 方法将被调用。该类在这个方法中包含了一个指向 FilterConfig 对象的引用。通过FilterConfig对象获得配置文件中设定的字符集。
部署Servlet过滤器,在web.xml文件中配置过滤器
<!--过滤器配置--> <filter> <filter-name>Encoder</filter-name> <filter-class>myproj.filter.SetCharacterEncodingFilter</filter-class> <!--初始化参数--> <init-param> <param-name>newcharset</param-name> <param-value>gb2312</param-value> </init-param> </filter> <!--过滤器与URL关联--> <filter-mapping> <filter-name>Encoder</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>编译SetCharacterEncodingFilter类,编译时,需要将Java Servlet API的包servlet-api.jar放到类路径中,编译后的类放到Web应用的WEB-INF\classes目录下,并且目录结构要与包的结构一致。
五、过滤器的应用
1、设置字符编码的过滤器:通过配置参数encoding指明使用何种字符编码,以处理页面的中文问题。
2、使用Filter实现URL级别的权限认证:在实际开发中我们经常把一些执行敏感操作的servlet映射到一些特殊目录中,并用filter把这些特殊目录保护起来,限制只能拥有相应访问权根的用户才能访问这些目录下的资源。
3、实现用户自动登陆的过滤器:在用户登陆成功后,发送一个名为user的cookie给客户端,cookie的值为用户名和加密后的密码。可以通过过滤器检查请求是否带有名称为user的cookie。如果有,则进行验证。
4、实现应用访问的日志:对于到达系统的所有请求,过滤器收集诸如浏览器类型、一天中的时间、转发 URL等相关信息,并对它们进行日志记录。
5、XSLT 转换:不管是使用移动客户端还是使用基于XML的Web服务,无需把逻辑嵌入应用程序就在XML语法之间执行转换的能力都绝对是无价的。
六、Servlet监听器用于监听一些重要事件的发生,监听器对象可以在事情发生前、发生后可以做一些必要的处理。
接口: 目前Servlet2.4和JSP2.0总共有8个监听器接口和6个Event类,
Listener与对应的Event如下所示:
1、ServletContextListener---ServletContextEvent
2、ServletContextAttributeListener---ServletContextAttributeEvent
3、HttpSessionListener---HttpSessionEvent
4、HttpSessionActivationListener---HttpSessionEvent
5、HttpSessionAttributeListener---HttpSessionBindingEvent
6、HttpSessionBindingListener---HttpSessionBindingEvent
7、ServletRequestListener--- ServletRequestEvent
8、ServletRequestAttributeListener---ServletRequestAttributeEvent
(一)ServletContext相关监听接口
通过ServletContext 的实例可以存取应用程序的全局对象以及初始化阶段的变量。 在JSP文件中,application 是 ServletContext 的实例,由JSP容器默认创建。Servlet 中调用 getServletContext()方法得到 ServletContext 的实例。 注意:全局对象即Application范围对象,初始化阶段的变量指在web.xml中,经由<context-param>元素所设定的变量,它的范围也是Application范围,例如:
<context-param>
<param-name>Name</param-name>
<param-value>browser</param-value>
</context-param>
当容器启动时,会建立一个Application范围的对象,若要在JSP网页中取得此变量时: String name = (String)application.getInitParameter("Name");
或者使用EL时: ${initPara.name} 若是在Servlet中,取得Name的值方法: String name = (String)ServletContext.getInitParameter("Name");
1、ServletContextListener: 用于监听WEB 应用启动和销毁的事件,监听器类需要实现javax.servlet.ServletContext
2、Listener 接口。ServletContextListener 是 ServletContext 的监听者,如果 ServletContext 发生变化,如服务器启动时 ServletContext 被创建,服务器关闭时 ServletContext 将要被销毁。
ServletContextListener接口的方法:
void contextInitialized(ServletContextEvent sce) 通知正在接受的对象,应用程序已经被加载及初始化。
void contextDestroyed(ServletContextEvent sce) 通知正在接受的对象,应用程序已经被载出。
ServletContextEvent中的方法:
ServletContext getServletContext() 取得ServletContext对象
ServletContextAttributeListener:用于监听WEB应用属性改变的事件,包括:增加属性、删除属性、修改属性,监听器类需要实现javax.servlet.ServletContextAttributeListener接口。
ServletContextAttributeListener接口方法:
void attributeAdded(ServletContextAttributeEvent scab) 若有对象加入Application的范围,通知正在收听的对象
void attributeRemoved(ServletContextAttributeEvent scab) 若有对象从Application的范围移除,通知正在收听的对象
void attributeReplaced(ServletContextAttributeEvent scab)
ServletContextAttributeEvent中的方法:
java.lang.String getName() 回传属性的名称
java.lang.Object getValue() 回传属性的值
二 、HttpSession相关监听接口
通过HttpSession的实例可以实现会话跟踪,HttpSession相关监听接口定义了与会话相关的处理。
1、HttpSessionBindingListener接口
注意:HttpSessionBindingListener接口是唯一不需要在web.xml中设定的Listener 当我们的类实现了HttpSessionBindingListener接口后,只要对象加入Session范围(即调用HttpSession对象的setAttribute方法的时候)或从Session范围中移出(即调用HttpSession对象的removeAttribute方法的时候或Session Time out的时候)时,容器分别会自动调用下列两个方法:
void valueBound(HttpSessionBindingEvent event)
void valueUnbound(HttpSessionBindingEvent event)
2、HttpSessionAttributeListener接口
HttpSessionAttributeListener监听HttpSession中的属性的操作。 当在Session增加一个属性时,激发attributeAdded(HttpSessionBindingEvent se) 方法;当在Session删除一个属性时,激发attributeRemoved(HttpSessionBindingEvent se)方法;当在Session属性被重新设置时,激发attributeReplaced(HttpSessionBindingEvent se) 方法。这和ServletContextAttributeListener比较类似。
3、HttpSessionListener接口
HttpSessionListener监听HttpSession的操作。当创建一个Session时,激发session Created(HttpSessionEvent se)方法;当销毁一个Session时,激发sessionDestroyed (HttpSessionEvent se)方法。4.HttpSessionActivationListener接口 主要用于同一个Session转移至不同的JVM的情形。
三、ServletRequest监听接口
1、ServletRequestListener接口 和ServletContextListener接口类似,该接口定义ServletRequest对象相关的操作。
2、ServletRequestAttributeListener接口 和ServletContextAttributeListener接口类似,只是该接口监听ServletRequest的属性变化。
以下实例MySessionListener用来监控会话(session)的变化。
package sample; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; import javax.servlet.http.HttpSessionActivationListener; import javax.servlet.http.HttpSessionBindingListener; import java.io.PrintWriter; import java.io.FileOutputStream; public final class MySessionListener implements HttpSessionActivationListener ,HttpSessionBindingListener , HttpSessionAttributeListener, HttpSessionListener,ServletContextListener { ServletContext context; int users=0; //HttpSessionActivationListener public void sessionDidActivate(HttpSessionEvent se) { logout("sessionDidActivate("+se.getSession().getId()+")"); } public void sessionWillPassivate(HttpSessionEvent se) { logout("sessionWillPassivate("+se.getSession().getId()+")"); }//HttpSessionActivationListener //HttpSessionBindingListener public void valueBound(HttpSessionBindingEvent event) { logout("valueBound("+event.getSession().getId()+event.getValue()+")"); } public void valueUnbound(HttpSessionBindingEvent event) { logout("valueUnbound("+event.getSession().getId()+event.getValue()+")"); } //HttpSessionAttributeListener public void attributeAdded(HttpSessionBindingEvent event) { logout("attributeAdded('" + event.getSession().getId() + "', '" + event.getName() + "', '" + event.getValue() + "')"); } public void attributeRemoved(HttpSessionBindingEvent event) { logout("attributeRemoved('" + event.getSession().getId() + "', '" +event.getName() + "', '" + event.getValue() + "')"); } public void attributeReplaced(HttpSessionBindingEvent se) { logout("attributeReplaced('"+se.getSession().getId()+",'"+se.getName()+"','"+se.getValue()+"')"); }//HttpSessionAttributeListener //HttpSessionListener public void sessionCreated(HttpSessionEvent event) { users++; logout("sessionCreated('" + event.getSession().getId() + "'),目前有"+users+"个用户"); context.setAttribute("users",new Integer(users)); } public void sessionDestroyed(HttpSessionEvent event) { users--; logout("sessionDestroyed('" + event.getSession().getId() + "'),目前有"+users+"个用户"); context.setAttribute("users",new Integer(users)); }//HttpSessionListener //ServletContextListener public void contextDestroyed(ServletContextEvent sce) { logout("contextDestroyed()-->ServletContext被销毁"); this.context = null; } public void contextInitialized(ServletContextEvent sce) { this.context = sce.getServletContext(); logout("contextInitialized()-->ServletContext初始化了"); }//ServletContextListener private void logout(String message) { PrintWriter out=null; try{ out=new PrintWriter(new FileOutputStream("d:\\temp\\session.txt",true)); out.println(new java.util.Date().toLocaleString()+"::Form MySessionListener: " + message); out.close(); } catch(Exception e) { out.close(); e.printStackTrace(); } } }
软件开发工程师(JAVA)中级考试大纲之----五 J2EE WEB高级组件开发(二)Web过滤器组件技术、Web监听器组件技术;
原文地址:http://blog.csdn.net/liuganggao/article/details/44056455