Filter 作用
你可以在两种情况下使用本文:学习过滤器的功用,作为你写过滤器时的辅助。我将从几个简单的例子开始然后继续更多高级的过滤器。最后,我将向你介绍我为了支持多路请求而写的一个文件上传过滤器。?Servlet 过滤器也许你还不熟悉情况,一个过滤器是一个可以传送请求或修改响应的对象。过滤器并不是servlet,他们并不实际创建一个请求。他们是请求到达一个servlet前的预处理程序,和/或响应离开servlet后的后处理程序。就像你将在后面的例子中看到的,一个过滤器能够:在一个servlet被调用前截获该调用在一个servlet被调用前检查请求修改在实际请求中提供了可定制请求对象的请求头和请求数据修改在实际响应中提供了可定制响应对象的响应头和响应数据在一个servlet被调用之后截获该调用???? 一个过滤器以作用于一个或一组servlet,零个或多个过滤器能过滤一个或多个servlet。一个过滤器需要实现java.servlet.Filter接口,并定义它的三个方法:1.????????????? void init(FilterConfig config) throws ServletException:在过滤器执行service前被调用,以设置过滤器的配置对象。2.????????????? void destroy();在过滤器执行service后被调用。3.????????????? Void doFilter(ServletRequest req,ServletResponse res,FilterChain chain) throws IOException,ServletException;执行实际的过滤工作。?服务器调用一次init(FilterConfig)以为服务准备过滤器,然后在请求需要使用过滤器的任何时候调用doFilter()。FilterConfig接口检索过滤器名、初始化参数以及活动的servlet上下文。服务器调用destory()以指出过滤器已结束服务。过滤器的生命周期和servelt的生命周期非常相似 ——在Servlet API 2.3 最终发布稿2号 中最近改变的。先前得用setFilterConfig(FilterConfig)方法来设置生命周期。?在doFilter()方法中,每个过滤器都接受当前的请求和响应,而FilterChain包含的过滤器则仍然必须被处理。doFilter()方法中,过滤器可以对请求和响应做它想做的一切。(就如我将在后面讨论的那样,通过调用他们的方法收集数据,或者给对象添加新的行为。)过滤器调用chain.doFilter()将控制权传送给下一个过滤器。当这个调用返回后,过滤器可以在它的doFilter()方法的最后对响应做些其他的工作;例如,它能记录响应的信息。如果过滤器想要终止请求的处理或得对响应的完全控制,则他可以不调用下一个过滤器。?循序渐进如果想要真正理解过滤器,则应该看它们在实际中的应用。我们将看到的第一个过滤器是简单而有用的,它记录了所有请求的持续时间。在Tomcat 4.0发布中被命名为ExampleFilter。代码如下:java 代码
- import?java.io.*; ?? import?javax.servlet.*; ??
- import?javax.servlet.http.*; ?? ? ??
- public?class?TimerFilter?implements?Filter?{ ?? ? ??
- ?private?FilterConfig?config?=?null; ?? ? ??
- ?public?void?init(FilterConfig?config)?throws?ServletException?{ ?? ????this.config?=?config; ??
- ?} ?? ? ??
- ?public?void?destroy()?{ ?? ????config?=?null; ??
- ?} ?? ? ??
- ?public?void?doFilter(ServletRequest?request,?ServletResponse?response, ?? ?????????????????????FilterChain?chain)?throws?IOException,?ServletException?{ ??
- ????long?before?=?System.currentTimeMillis(); ?? ????chain.doFilter(request,?response); ??
- ????long?after?=?System.currentTimeMillis(); ?? ? ??
- ????String?name?=?""; ?? ????if?(request?instanceof?HttpServletRequest)?{ ??
- ??????name?=?((HttpServletRequest)request).getRequestURI(); ?? ????} ??
- ????config.getServletContext().log(name?+?":?"?+?(after?-?before)?+?"ms"); ?? ?} ??
- } ??
- <filter>?? ???????<filter-name>timerFilterfilter-name>??
- ???????<filter-class>TimerFilterfilter-class>?? /filter>??
- <filter-mapping>?? ????<filter-name>timerFilterfilter-name>??
- ????<url-pattern>/*url-pattern>?? filter-mapping>??
- import?java.io.IOException; ?? import?javax.servlet.*; ??
- import?javax.servlet.http.*; ?? ? ??
- public?class?ClickstreamFilter?implements?Filter?{ ?? ?protected?FilterConfig?filterConfig; ??
- ?private?final?static?String?FILTER_APPLIED?=?"_clickstream_filter_applied"; ?? ? ??
- ?public?void?init(FilterConfig?config)?throws?ServletException?{ ?? ????this.filterConfig?=?filterConfig; ??
- ?} ?? ? ??
- ?public?void?doFilter(ServletRequest?request,?ServletResponse?response, ?? ???????????????????FilterChain?chain)?throws?IOException,?ServletException?{ ??
- ????//?确保该过滤器在每次请求中只被使用一次 ?? ????if?(request.getAttribute(FILTER_APPLIED)?==?null)?{ ??
- ??????request.setAttribute(FILTER_APPLIED,?Boolean.TRUE); ?? ??????HttpSession?session?=?((HttpServletRequest)request).getSession(); ??
- ??????Clickstream?stream?=?(Clickstream)session.getAttribute("clickstream"); ?? ??????stream.addRequest(((HttpServletRequest)request)); ??
- ????} ?? ? ??
- ????//?传递请求 ?? ????chain.doFilter(request,?response); ??
- ?} ?? ? ??
- ?public?void?destroy()?{?} ?? } ??
- import?java.util.*; ?? import?javax.servlet.*; ??
- import?javax.servlet.http.*; ?? ? ??
- public?class?ClickstreamLogger?implements?ServletContextListener, ?? ??????????????????????????????????????????HttpSessionListener?{ ??
- ?Map?clickstreams?=?new?HashMap(); ?? ? ??
- ?public?ClickstreamLogger()?{?} ?? ? ??
- ?public?void?contextInitialized(ServletContextEvent?sce)?{ ?? ????sce.getServletContext().setAttribute("clickstreams",?clickstreams); ??
- ?} ?? ? ??
- ?public?void?contextDestroyed(ServletContextEvent?sce)?{ ?? ????sce.getServletContext().setAttribute("clickstreams",?null); ??
- ?} ?? ? ??
- ?public?void?sessionCreated(HttpSessionEvent?hse)?{ ?? ????HttpSession?session?=?hse.getSession(); ??
- ????Clickstream?clickstream?=?new?Clickstream(); ?? ????session.setAttribute("clickstream",?clickstream); ??
- ????clickstreams.put(session.getId(),?clickstream); ?? ?} ??
- ? ?? ?public?void?sessionDestroyed(HttpSessionEvent?hse)?{ ??
- ????HttpSession?session?=?hse.getSession(); ?? ????Clickstream?stream?=?(Clickstream)session.getAttribute("clickstream"); ??
- ????clickstreams.remove(session.getId()); ?? ?} ??
- } ??
- <filter>?? ?????????<filter-name>clickstreamFilterfilter-name>??
- ?????????<filter-class>ClickstreamFilterfilter-class>?? ????filter>??
- ????<filter-mapping>?? ?????????<filter-name>clickstreamFilterfilter-name>??
- ?????????<url-pattern>*.jspurl-pattern>?? ????filter-mapping>??
- ????<filter-mapping>?? ?????????<filter-name>clickstreamFilterfilter-name>??
- ?????????<url-pattern>*.htmlurl-pattern>?? ????filter-mapping>??
- ????<listener>?? ?????????<listener-class>ClickstreamLoggerlistener-class>??
- ????listener>??
- <%@?page?import="java.util.*"?%> ?? <%@?page?import="Clickstream"?%> ??
- <% ?? Map?clickstreams?=?(Map)application.getAttribute("clickstreams"); ??
- String?showbots?=?"false"; ?? if?(request.getParameter("showbots")?!=?null)?{ ??
- ??if?(request.getParameter("showbots").equals("true")) ?? ????showbots?=?"true"; ??
- ??else?if?(request.getParameter("showbots").equals("both")) ?? ????showbots?=?"both"; ??
- } ?? %> ??
- <font?face="Verdana"?size="-1"> ?? <h1>All?Clickstreams</h1> ??
- <a?href="clickstreams.jsp?showbots=false">No?Bots</a>?| ?? <a?href="clickstreams.jsp?showbots=true">All?Bots</a>?| ??
- <a?href="clickstreams.jsp?showbots=both">Both</a>?<p> ?? <%?if?(clickstreams.keySet().size()?==?0)?{?%> ??
- ????????No?clickstreams?in?progress ?? <%?}?%> ??
- <% ?? Iterator?it?=?clickstreams.keySet().iterator(); ??
- int?count?=?0; ?? while?(it.hasNext())?{ ??
- ??String?key?=?(String)it.next(); ?? ??Clickstream?stream?=?(Clickstream)clickstreams.get(key); ??
- ??if?(showbots.equals("false")?&&?stream.isBot())?{ ?? ????continue; ??
- ??}else?if?(showbots.equals("true")?&&?!stream.isBot())?{ ?? ????continue; ??
- ??} ?? ??count++; ??
- ??try?{ ?? %> ??
- ?? <%=?count?%>.? ??
- <a?href="viewstream.jsp?sid=<%=?key?%>"><b> ?? <%=?(stream.getHostname()?!=?null?&&?!stream.getHostname().equals("")?? ??
- ?????stream.getHostname()?:?"Stream")?%> ?? </b></a>?<font?size="-1">[<%=?stream.getStream().size()?%>?reqs]</font><br> ??
- ?? <% ??
- ??}catch?(Exception?e)?{ ?? %> ??
- ??An?error?occurred?-?<%=?e?%><br> ?? <% ??
- ??} ?? } ??
- %>??
WEB-INF/classes下,将JSP文件放到Web应用路径下,按帮助修改web.xml文件。为防止在这些工作前的争论,你可以从这个包很容易从OpenSymphony下载并安装。将Java文件编译并放在
http://www.javaworld.com/jw-06-2001/Filters/clickstream.war处找到打好包的WAR文件。?为能让此过滤器能在Tomcat 4.0 beta 5下工作,我发现我不得不做一些轻微的改动。我做的改动显示了一些在servlet和过滤器的可移植性中通常容易犯的错误,所以我将他们列在下面:我不得不将在JSP中添加一个额外的导入语句:<!---->。在Java中你并不需要导入在同一包下的类,而在服务器上JSP被编译到默认包中,你并不需要这句导入行。但在像Tomcat这样的服务器上,JSP被编译到一个自定义的包中,你不得不明确地从默认包中导入类。我不得不将 <listener></listener> 元素移动到web.xml文件中的<filter></filter>和<filter-mapping></filter-mapping>元素之后,就像部署描述DTD要求的那样。并不是所有服务器对元素都要求固定的顺序。但Tomcat必须要。我不得不将web.xml中的映射由/*.html和/*.jsp改成正确的*.html和*.jsp。一些服务器会忽略开头的/,但Tomcat强硬的规定开头不能有/。最后,我得将ClickstreamFilter类升级到最新的生命周期API,将setFilterConfig()改成新的init()和destory()方法。?可下载的WAR文件已经包含了这些修改并能通过服务器在包外运行,虽然我并没有广泛的进行测试。?压缩响应第三个过滤器是自动压缩响应输出流,以提高带宽利用率并提供一个很好的包装响应对象的示例。这个过滤器是由来自SUN的Amy Roh编写的,他为Tomcat 4.0 的“examples”Web程序做出过贡献。你将从webapps/examples/WEB-INF/classes/compressionFilters下找到原始代码。这里的例子代码以及WAR下的都已经为了更清晰和更简单而编辑过了。?CompressionFilter类的策略是检查请求头以判定客户端是否支持压缩,如果支持,则将响应对象用自定义的响应来打包,它的getOutputStream()和getWriter()方法已经被定义为可以利用压缩过的输出流。使用过滤器允许如此简单而有效的解决问题。?我们将从init()开始看代码:- public?void?init(FilterConfig?filterConfig)?{ ?? ???config?=?filterConfig; ??
- ???compressionThreshold?=?0; ?? ???if?(filterConfig?!=?null)?{ ??
- ?????String?str?=?filterConfig.getInitParameter("compressionThreshold"); ?? ?????if?(str?!=?null)?{ ??
- ???????compressionThreshold?=?Integer.parseInt(str); ?? ?????} ??
- ?????else?{ ?? ???????compressionThreshold?=?0; ??
- ?????} ?? ???} ??
- }??
- public?class?CompressionResponseWrapper?extends?HttpServletResponseWrapper?{ ?? ? ??
- ?protected?ServletOutputStream?stream?=?null; ?? ?protected?PrintWriter?writer?=?null; ??
- ?protected?int?threshold?=?0; ?? ?protected?HttpServletResponse?origResponse?=?null; ??
- ? ?? ?public?CompressionResponseWrapper(HttpServletResponse?response)?{ ??
- ????super(response); ?? ????origResponse?=?response; ??
- ?} ?? ? ??
- ?public?void?setCompressionThreshold(int?threshold)?{ ?? ????this.threshold?=?threshold; ??
- ?} ?? ? ??
- ?public?ServletOutputStream?createOutputStream()?throws?IOException?{ ?? ????return?(new?CompressionResponseStream(origResponse)); ??
- ?} ?? ? ??
- ?public?ServletOutputStream?getOutputStream()?throws?IOException?{ ?? ????if?(writer?!=?null)?{ ??
- ??????throw?new?IllegalStateException("getWriter()?has?already?been?"?+ ?? ??????????????????????????????????????"called?for?this?response"); ??
- ????} ?? ? ??
- ????if?(stream?==?null)?{ ?? ??????stream?=?createOutputStream(); ??
- ????} ?? ????((CompressionResponseStream)?stream).setCommit(true); ??
- ????((CompressionResponseStream)?stream).setBuffer(threshold); ?? ????return?stream; ??
- ?} ?? ? ??
- ?public?PrintWriter?getWriter()?throws?IOException?{ ?? ????if?(writer?!=?null)?{ ??
- ??????return?writer; ?? ????} ??
- ? ?? ????if?(stream?!=?null)?{ ??
- ??????throw?new?IllegalStateException("getOutputStream()?has?already?"?+ ?? ??????????????????????????????????????"been?called?for?this?response"); ??
- ????} ?? ? ??
- ????stream?=?createOutputStream(); ?? ????((CompressionResponseStream)?stream).setCommit(true); ??
- ????((CompressionResponseStream)?stream).setBuffer(threshold); ?? ????writer?=?new?PrintWriter(stream); ??
- ????return?writer; ?? ?} ??
- } ??
- <filter>?? ????<filter-name>compressionFilterfilter-name>??
- ????<filter-class>CompressionFilterfilter-class>?? ????<init-param>??
- ??????<param-name>compressionThresholdparam-name>?? ??????<param-value>10param-value>??
- ????init-param>?? filter>??
- ?? <filter-mapping>??
- ????<filter-name>compressionFilterfilter-name>?? ????<servlet-name>compressionTestservlet-name>??
- filter-mapping>?? ??
- <servlet>?? ??<servlet-name>??
- ????compressionTest ?? ??servlet-name>??
- ??<servlet-class>?? ????CompressionTestServlet ??
- ??servlet-class>?? servlet>??