- 浏览: 89592 次
最新评论
-
守望者:
我也是出现了同样的错误,应该不是楼上这位仁兄说的Tomcat的 ...
appfuse 1.9.4 错误 -
huanghero0663:
不是tomcat的问题,而是你在电脑上的环境变量写错了,app ...
appfuse 1.9.4 错误
你可以在两种情况下使用本文:
·学习过滤器的功用,
·作为你写过滤器时的辅助。
我将从几个简单的例子开始然后继续更多高级的过滤器。最后,我将向你介绍我为了支持多路请求而写的一个文件上传过滤器。
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");
- }
- }
当服务器调用init()时,过滤器用config变量来保存配置类的引用,这将在后面的doFilter()方法中被使用以更改ServletContext。当调用doFilter()时,过滤器计算请求发出到该请求执行完毕之间的时间。该过滤器很好的演示了请求之前和之后的处理。注意doFilter()方法的参数并不是HTTP对象,因此要调用HTTP专用的getRequestURI()方法时必须将request转化为HttpServletRequest类型。
使用此过滤器,你还必须在web.xml文件中用<filter></filter>标签部署它,见下:
- <filter>
- <filter-name>timerFilterfilter-name>
- <filter-class>TimerFilterfilter-class>
- /filter>
这将通知服务器一个叫timerFiter的过滤器是从TimerFiter类实现的。你可以使用确定的URL模式或使用<filter-mapping></filter-mapping>标签命名的servelt 来注册一个过滤器,如:
CompressionTestServlet(这里没有显示)输出压缩是否可用,如果可用,则输出压缩响应成功!
- <filter-mapping>
- <filter-name>timerFilterfilter-name>
- <url-pattern>/*url-pattern>
- filter-mapping>
这种配置使过滤器操作所有对服务器的请求(静态或动态),正是我们需要的计时过滤器。如果你连接一个简单的页面,记录输出可能如下:
2001-05-25 00:14:11 /timer/index.html: 10ms
在Tomcat 4.0 beta 5中,你可以在server_root/logs/下找到该记录文件。
此过滤器的WAR文件从此下载:
谁在你的网站上?他们在做什么?
我们下一个过滤器是由OpenSymphony成员写的clickstream过滤器。这个过滤器跟踪用户请求(比如:点击)和请求队列(比如:点击流)以向网络管理员显示谁在她的网站上以及每个用户正在访问那个页面。这是个使用LGPL的开源库。
在clickstream包中你将发现一个捕获请求信息的ClickstreamFilter类,一个像操作结构一样的Clickstream类以保存数据,以及一个保存会话和上下文事件的ClickstreamLogger类以将所有东西组合在一起。还有个BotChecker类用来确定客户端是否是一个机器人(简单的逻辑,像“他们是否是从robots.txt来的请求?”)。该包中提供了一个clickstreams.jsp摘要页面和一个viewstream.jsp详细页面来查看数据。
我们先看ClickstreamFilter类。所有的这些例子都做了些轻微的修改以格式化并修改了些可移植性问题,这我将在后面将到。
- 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() { }
- }
doFilter()方法取得用户的session,从中获取Clickstream,并将当前请求数据加到Clickstream中。其中使用了一个特殊的FILTER_APPLIED标记属性来标注此过滤器是否已经被当前请求使用(可能会在请求调度中发生)并且忽略所有其他的过滤器行为。你可能疑惑过滤器是怎么知道当前session中有clickstream属性。那是因为ClickstreamLogger在会话一开始时就已经设置了它。ClickstreamLogger代码:
- 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());
- }
- }
logger(记录器)获取应用事件并将使用他们将所有东西帮定在一起。当context创建中,logger在context中放置了一个共享的流map。这使得clickstream.jsp页面知道当前活动的是哪个流。而在context销毁中,logger则移除此map。当一个新访问者创建一个新的会话时,logger将一个新的Clickstream实例放入此会话中并将此Clickstream加入到中心流map中。在会话销毁时,由logger从中心map中移除这个流。
下面的web.xml部署描述片段将所有东西写在一块:
- <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>
这注册了ClickstreamFilter并设置其处理*.jsp和*.html来的请求。这也将ClickstreamLogger注册为一个监听器以在应用事件发生时接受他们。
两个JSP页面从会话中取clickstream数据和context对象并使用HTML界面来显示当前状态。下面的clickstream.jsp文件显示了个大概:
js 代码
- <%@ 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文件编译并放在
为能让此过滤器能在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;
- }
- }
- }
注意在检索请求头前必须把request转化为HttpServletRequest,就想在第一个例子里那样。过滤器使用wrapper类CompressResponseWrapper,一个从
HttpServletResponseWrapper类继承下来的自定义类。这个wrapper的代码相对比较简单:
- 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;
- }
- }
所有调用getOutputStream() 或者getWriter()都返回一个使用
CompressResponseStream类的对象。CompressionResponseStrteam类没有显示在这个例子中,因为它继承于ServletOutputStream并使用java.util.zip.GZIPOutputStream类来压缩流。
Tomcat的”examples”Web程序中已经预先配置了这个压缩过滤器并加载了一个示例servlet。示例servlet响应/CompressionTestURL(确定先前的路径是/examples)。使用我制作的有用的WAR文件,你可以用/servlet/compressionTest(再次提醒,别忘了适当的前导路径)访问此测试servlet。你可以使用如下的web.xml片段来配置这个测试:
<filter></filter>
xml 代码
- <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>
发表评论
-
出现java.lang.UnsupportedClassVersionError 错误的原因
2007-04-18 13:55 2285出现java.lang.UnsupportedClassVer ... -
log4cplus学习笔记(二)
2007-03-27 13:11 8816log4cplus在很多方面做的都很出色,但是使用过程有些地 ... -
log4cplus学习笔记(一)
2007-03-27 13:00 59071(一)log4cplus是C++编写的开源的日志系统,功能非常 ... -
Java基础知识总结
2007-02-08 16:32 181、对象的初始化 ... -
Java及相关字符集编码问题研究
2007-01-09 10:45 12071. ... -
编写安全的Java代码
2007-01-09 09:54 1258本文是来自Sun官方站点的一篇关于如何编写安全的Java代码的 ... -
Filter学习2
2006-12-14 16:40 1707Servlet2.3 Filter 1、Se ... -
java 日期的处理2
2006-12-12 11:22 63cal1.add(Calendar.WEEK_OF_ ... -
关于Oracle9i日期格式几点要说明的问题
2006-12-12 11:02 751. 在 Oracle9i 之前, 日期格式的数据类型默认格式 ... -
java 日期的处理1
2006-12-12 11:22 40java中常见的日期时间类 Date 类 最基础的日期时间 ... -
SQL语句集
2006-12-12 10:35 62--语 句 功 能 --数据操作 S ... -
JDBC
2006-12-11 11:47 54java 代码 String strDri ...
相关推荐
MATLAB 滤波 用于图像处理 噪声处理 图像增强等
叙述了MATLAB中几种相关函数的用法,对filter conv 和impz函数进行了介绍
File Based Write Filter(FBWF)可以使用FBWF保护并提速系统,保护固态盘 一键安装,使用系统win7 8 10(x86 x64)
-- 此处可配合我的这篇文章来理解各个过滤连的作用http://blog.csdn.net/jadyer/article/details/12172839 --> <!-- 下面value值的第一个'/'代表的路径是相对于HttpServletRequest.getContextPath()的值来的...
Duanxx的OpenCV学习:filter2D使用说明
1. Filter 1.1.概念: web 中的过滤器:当访问服务器的资源时,过滤器可以将请求拦 截下来,完成一些特殊的功能。 过滤器的作用: 用于完成通用的操作。如:登录验证、统一编码处理、敏感字符过滤 2. 动态代理 2.1....
Kalman filter 学习源代码,对于学习卡尔曼滤波器的同志有很好指导作用 Kalman filter toolbox written by Kevin Murphy
FSFD(一个比较价值的File system Filter Driver)
unity滤镜插件免费分享,Camera Filter Pack 4.0.0.unitypackage,方便快捷地添加各种滤镜效果
一、过滤器的作用和概述 1.1 简述 1.2 使用场景 二、自定义过滤的两种方式 2.1 第一种方式 2.1.1 启动类增加注解@ServletComponentScan 2.1.2 定义一个filter类 2.1.3. 测试 2.2 第二种方式 2.2.1 自定义fitler类 ...
代码中添加editgraph(),运行后,再启动graphstudio ,可以查看当前的流媒体使用的com及依赖的dll。 filmerit_31en.exe ,用于对filter进行管理和修改。需要在管理员模式下使用才能作用到注册表中。
Filter作用就是接收一个输入,通过某个规则进行处理,然后给用户返回处理后的结果。Filter可以用在模板、控制器、或者服务,同时也会很容易自定义一个Filter过滤器。 在模板中使用Filter Filter可以用于在视图模板...
培训主要学习以下几个知识点: 1.Filter简介 2.Filter基本工作原理 3.Filter的主要作用及Filter API 4.Filter接口 5.FilterChain接口 6.FilterConfig接口 7.Filter的部署 8.Filter的典型应用
1、Filter 什么是过滤器 3、Filter 过滤器它的作用是:拦截请求,过滤响应 1、权限检查 2、日记操作 3、事务管理 1、编写一个类去实现 Filt
servlet过滤器Filter入门,Servle过滤器的使用是Servlet中的重要内容,此文档就是针对此内容编写的。
滤波器设计软件,对于设计模拟数字电路作用很大。方便使用。
NoFilter是一种抗审查的共享工具,它使用IPFS和以太坊区块链来自由共享信息。设置方法: 克隆仓库,进入目录并安装节点软件包。 git clone 否过滤器cd无滤镜npm安装安装松露npm install -g松露开始松露松露发育运行...
点云滤波是点云处理的基本步骤,也是进行 high level 三维图像处理之前必须要进行的预处理。其作用类似于信号处理中的滤波,但实现手段却和信号处理不一样。点云不是函数,对于复杂三维外形其x
JAVA过滤器filter request.setCharacterEncoding仅对POST提交起作用,对GET提交还是会出现乱码问题
bloomfilter-rb rubygem(在JRuby下不起作用) 使用: 将此添加到您的Gemfile中: gem 'fast-filter', :git => 'git://github.com/mobmewireless/fast-filter.git' 然后: require 'fast-filter' 要:需要...