Servlet 2.3过滤器编程[转]

最新推荐文章于 2020-11-18 11:11:26 发布
原创 最新推荐文章于 2020-11-18 11:11:26 发布 · 6.5k 阅读
· 0
· 2 ·
CC 4.0 BY-SA版权
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
文章标签:

#servlet #wrapper #import #string #stream #filter

Java 专栏收录该内容
418 篇文章
订阅专栏
本文深入探讨了Servlet过滤器,介绍其工作原理和用途。通过记录请求时长的TimerFilter、跟踪用户请求的ClickstreamFilter,以及简化文件上传的MultipartFilter等实例,展示了过滤器在请求预处理和响应后处理中的作用,还提及了部署和使用方法。

摘要

Jason Hunter通过对一些自由而又实用的过滤器的研究以对新的servlet过滤器模型进行深入探讨。你将知道这些过滤器是如何工作以及你能用他们做什么。最后,Jason介绍了他自己为简化文件上传而做的多路请求过滤器。 

在"Servlet 2.3: New Features Exposed,"中,我介绍了Servlet API 2.3中的变化并给出了一个简单的servlet过滤器模型。在随后的文章中,我将对servlet过滤器进行深入的挖掘,而你看到的这些servlet过滤器都是能从Web上免费下载的。对每一个过滤器,我将检视它是做什么的,如何工作的,以及你能从哪里得到它。

 

你可以在两种情况下使用本文:学习过滤器的功用,或者作为你写过滤器时的辅助。我将从几个简单的例子开始然后继续更多高级的过滤器。最后,我将向你介绍我为了支持多路请求而写的一个文件上传过滤器。

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。代码如下:

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-name>timerFilter</filter-name>

        <filter-class>TimerFilter</filter-class>

</filter>

 

这将通知服务器一个叫timerFiter的过滤器是从TimerFiter类实现的。你可以使用确定的URL模式或使用<filter-mapping>标签命名的servelt 来注册一个过滤器,如:

<filter-mapping>

    <filter-name>timerFilter</filter-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文件从此下载:

    http://www.javaworld.com/jw-06-2001/Filters/timer.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>clickstreamFilter</filter-name>

         <filter-class>ClickstreamFilter</filter-class>

    </filter>

 

    <filter-mapping>

         <filter-name>clickstreamFilter</filter-name>

         <url-pattern>*.jsp</url-pattern>

    </filter-mapping>

 

    <filter-mapping>

         <filter-name>clickstreamFilter</filter-name>

         <url-pattern>*.html</url-pattern>

    </filter-mapping>

 

    <listener>

         <listener-class>ClickstreamLogger</listener-class>

    </listener>

 

    这注册了ClickstreamFilter并设置其处理*.jsp和*.html来的请求。这也将ClickstreamLogger注册为一个监听器以在应用事件发生时接受他们。

 

   两个JSP页面从会话中取clickstream数据和context对象并使用HTML界面来显示当前状态。下面的clickstream.jsp文件显示了个大概:

<%@ 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>

<%

  }

}

%>

 

这个包很容易从OpenSymphony下载并安装。将Java文件编译并放在

WEB-INF/classes下,将JSP文件放到Web应用路径下,按帮助修改web.xml文件。为防止在这些工作前的争论,你可以从

http://www.javaworld.com/jw-06-2001/Filters/clickstream.war处找到打好包的WAR文件。

 

为能让此过滤器能在Tomcat 4.0 beta 5下工作,我发现我不得不做一些轻微的改动。我做的改动显示了一些在servlet和过滤器的可移植性中通常容易犯的错误,所以我将他们列在下面:

·我不得不将在JSP中添加一个额外的导入语句:<%@ page import=”Clickstream” %>。在Java中你并不需要导入在同一包下的类,而在服务器上JSP被编译到默认包中,你并不需要这句导入行。但在像Tomcat这样的服务器上,JSP被编译到一个自定义的包中,你不得不明确地从默认包中导入类。

·我不得不将<listener>元素移动到web.xml文件中的<filter>和<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-name>compressionFilter</filter-name>

    <filter-class>CompressionFilter</filter-class>

    <init-param>

      <param-name>compressionThreshold</param-name>

      <param-value>10</param-value>

    </init-param>

</filter>

 

<filter-mapping>

    <filter-name>compressionFilter</filter-name>

    <servlet-name>compressionTest</servlet-name>

</filter-mapping>

 

<servlet>

  <servlet-name>

    compressionTest

  </servlet-name>

  <servlet-class>

    CompressionTestServlet

  </servlet-class>

</servlet>

 

CompressionTestServlet(没有在这里列出)输出压缩是否可用,如果可用,则输出压缩响应成功!

文件上传过滤器

我们将看到的最后一个过滤器是处理多路/多类型数据的POST请求,该类型的请求能包含文件上传。每个多路/多类型数据POST请求包含所有参数和文件,使用一种servlet不能识别的特别的格式。历史上Servlet开发者使用第三方类来处理上传,例如在我的com.oreilly.servlet包中的MultipartRequest和MultipartParser类。这里我们将看到一种使用MultipartFilter的新方法来是处理这种请求更容易。该过滤器基于com.oreilly.servlet包下的parsers构建并已经被集成到该包中(参见Resources)。

 

MultipartFilter工作与观察输入的请求,当它发现一个文件上传请求时(content type:multipart/form-data),过滤器使用一个知道如何分析这种特殊content type格式的特殊请求包来将请求对象进行包装。servlet获取此特殊请求包并通过标准的getParameter()方法来无缝地访问此multipart参数,因为这个wrapper中已经重新定义了这些方法的功能。此servelt能够通过将requset转换成wrapper类型并使用wrapper中附加的getFile()方法来处理文件上传。

 

过滤器代码:

package com.oreilly.servlet;

 

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

 

public class MultipartFilter implements Filter {

 

  private FilterConfig config = null;

  private String dir = null;

 

  public void init(FilterConfig config) throws ServletException {

    this.config = config;

 

    // Determine the upload directory.  First look for an uploadDir filter

    // init parameter.  Then look for the context tempdir.

    dir = config.getInitParameter("uploadDir");

    if (dir == null) {

      File tempdir = (File) config.getServletContext()

                  .getAttribute("javax.servlet.context.tempdir");

      if (tempdir != null) {

        dir = tempdir.toString();

      }

      else {

        throw new ServletException(

          "MultipartFilter: No upload directory found: set an uploadDir " +

          "init parameter or ensure the javax.servlet.context.tempdir " +

          "directory is valid");

      }

    }

  }

 

  public void destroy() {

    config = null;

  }

 

  public void doFilter(ServletRequest request, ServletResponse response,

                     FilterChain chain) throws IOException, ServletException {

    HttpServletRequest req = (HttpServletRequest) request;

    String type = req.getHeader("Content-Type");

 

    // If this is not a multipart/form-data request continue

    if (type == null || !type.startsWith("multipart/form-data")) {

      chain.doFilter(request, response);

    }

    else {

      MultipartWrapper multi = new MultipartWrapper(req, dir);

      chain.doFilter(multi, response);

    }

  }

}

 

init()方法确定文件上传的路径。这是multipart parser放置文件的地方,因此实际的请求并不需要驻留在内存中。它先查找uploadDir过滤器初始化参数,如果没找到,则使用默认的tempdir目录——Servlet API 2.2中的标准context属性。

 

doFilter()方法检查请求的content type,如果是multipart/form-data请求,则将此请求用MultipartWrapper打包。wrapper代码如下:

package com.oreilly.servlet;

 

import java.io.*;

import java.util.*;

import javax.servlet.*;

import javax.servlet.http.*;

 

public class MultipartWrapper extends HttpServletRequestWrapper {

 

  MultipartRequest mreq = null;

 

  public MultipartWrapper(HttpServletRequest req, String dir)

                                     throws IOException {

    super(req);

    mreq = new MultipartRequest(req, dir);

  }

 

  // Methods to replace HSR methods

  public Enumeration getParameterNames() {

    return mreq.getParameterNames();

  }

  public String getParameter(String name) {

    return mreq.getParameter(name);

  }

  public String[] getParameterValues(String name) {

    return mreq.getParameterValues(name);

  }

  public Map getParameterMap() {

    Map map = new HashMap();

    Enumeration enum = getParameterNames();

    while (enum.hasMoreElements()) {

      String name = (String) enum.nextElement();

      map.put(name, mreq.getParameterValues(name));

    }

    return map;

  }

 

  // Methods only in MultipartRequest

  public Enumeration getFileNames() {

    return mreq.getFileNames();

  }

  public String getFilesystemName(String name) {

    return mreq.getFilesystemName(name);

  }

  public String getContentType(String name) {

    return mreq.getContentType(name);

  }

  public File getFile(String name) {

    return mreq.getFile(name);

  }

}

 

wrapper构造了一个com.oreilly.servlet.MultipartRequest对象以处理上传分析并重载getParameter()方法族以使用MultipartRequest取代未加工的请求来读取参数值。wrapper也定义了不同的getFile()方法以使一个servlet接收打包过的请求以能通过调用其他方法来处理上传的文件。

 

Web.xml部署描述器用如下代码来添加此过滤器:

<filter>

    <filter-name>multipartFilter</filter-name>

    <filter-class>com.oreilly.servlet.MultipartFilter</filter-class>

    <!--

    <init-param>

      <param-name>uploadDir</param-name>

      <param-value>/tmp</param-value>

    </init-param>

    -->

</filter>

 

<filter-mapping>

    <filter-name>multipartFilter</filter-name>

    <url-pattern>/*</url-pattern>

</filter-mapping>

 

<servlet>

    <servlet-name>

        uploadTest

    </servlet-name>

    <servlet-class>

        UploadTest

    </servlet-class>

</servlet>

 

<servlet-mapping>

    <servlet-name>

        uploadTest

    </servlet-name>

    <url-pattern>

        /uploadTest

    </url-pattern>

</servlet-mapping>

 

UploadText servlet如下:

import java.io.*;

import java.util.*;

import javax.servlet.*;

import javax.servlet.http.*;

 

import com.oreilly.servlet.*;

 

public class UploadTest extends HttpServlet {

 

  public void doPost(HttpServletRequest req, HttpServletResponse res)

                                throws ServletException, IOException {

    res.setContentType("text/html");

    PrintWriter out = res.getWriter();

 

    out.println("<HTML>");

    out.println("<HEAD><TITLE>UploadTest</TITLE></HEAD>");

    out.println("<BODY>");

    out.println("<H1>UploadTest</H1>");

 

    // Parameters can now be read the same way for both

    // application/x-www-form-urlencoded and multipart/form-data requests!

 

    out.println("<H3>Request Parameters:</H3><PRE>");

    Enumeration enum = req.getParameterNames();

    while (enum.hasMoreElements()) {

      String name = (String) enum.nextElement();

      String values[] = req.getParameterValues(name);

      if (values != null) {

        for (int i = 0; i < values.length; i++) {

          out.println(name + " (" + i + "): " + values[i]);

        }

      }

    }

    out.println("</PRE>");

 

    // Files can be read if the request class is MultipartWrapper

    // Init params to MultipartWrapper control the upload handling

 

    if (req instanceof MultipartWrapper) {

      try {

        // Cast the request to a MultipartWrapper

        MultipartWrapper multi = (MultipartWrapper) req;

 

        // Show which files we received

        out.println("<H3>Files:</H3>");

        out.println("<PRE>");

        Enumeration files = multi.getFileNames();

        while (files.hasMoreElements()) {

          String name = (String)files.nextElement();

          String filename = multi.getFilesystemName(name);

          String type = multi.getContentType(name);

          File f = multi.getFile(name);

          out.println("name: " + name);

          out.println("filename: " + filename);

          out.println("type: " + type);

          if (f != null) {

            out.println("length: " + f.length());

          }

          out.println();

        }

        out.println("</PRE>");

      }

      catch (Exception e) {

        out.println("<PRE>");

        e.printStackTrace(out);

        out.println("</PRE>");

      }

    }

 

    out.println("</BODY></HTML>");

  }

}

 

servlet的前一半显示了过滤器如何将参数数据毫无改变的传送给接收的servlet。后半部分则显示了一个servlet是如何将请求向下传送给MultipartWrapper以获得附加的文件访问方法。

 

一个驱动此servlet的HTML例子如下:

<FORM ACTION="uploadTest" ENCTYPE="multipart/form-data" METHOD=POST>

What is your name? <INPUT TYPE=TEXT NAME=submitter> <BR>

What is your age? <INPUT TYPE=TEXT NAME=age> <BR>

Which file do you want to upload? <INPUT TYPE=FILE NAME=file1> <BR>

Any other file to upload? <INPUT TYPE=FILE NAME=file2> <BR>

<INPUT TYPE=SUBMIT>

</FORM>

 

这是可能的输出:

UploadTest

Request Parameters:

submitter (0): Jason

age (0): 28

 

Files:

name: file1

filename: 4008b21.tif

type: application/octet-stream

length: 39396

 

name: file2

filename: null

type: null

 

你们也许会疑惑我们如何确信由过滤器设置的MultipartWrapper能正确的传送给接下来的servlet。在2号发布稿规范和Tomcat 4.0 beta 5中,那是不确定的。实际上,如果你试图用/servlet/UploadTest去访问此servlet,你将注意到过滤并没有正确工作,因为/servlet的调用将MultipartWrapper转给Tomcat自己的特殊wrapper了。这允许参数能被正确解析,但文件访问方法却不能正确工作。在Servlet API专家组的讨论中,我们决定servlet容器不能对过滤器的wrapper做更多的包装。这个servlet规范将被修改的更清楚。在Tomcat 4.0以后版本中将澄清这些规则。短期的办法是在请求wrapper中使用getRequest()方法来“沿着”请求去找到这个隐藏的multipart wrapper。

 

从如下地址下载该WAR文件:

http://www.javaworld.com/jw-06-2001/Filters/multipart.war

 

过滤器能力

Servlet过滤器提供了一中强大的能力来控制请求的操作和响应的发生,提供新的servlet功能而不需要太多的代码。我希望通过这些已经向你展示使用过滤器的可能情况,并教给你一些关于如何更有效的使用新的过滤器机能的技巧。

确定要放弃本次机会?
福利倒计时
: :

立减 ¥

普通VIP年卡可用
立即使用
chensheng913
关注 关注
  • 0
    点赞
  • 踩
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
  • 分享
    复制链接
    分享到 QQ
    分享到新浪微博
    扫一扫
  • 举报
    举报
专栏目录
Wireshark网络分析实战笔记(一)抓包过滤器
microminor
04-02 7495
抓包过滤器 抓包过滤器和显示过滤器的区别: 1.抓包过滤器配置在抓包之前,wireshark只抓取抓包过滤器过滤的数据 2.显示过滤器配置在抓包后,wireshark已经抓取所有的数据包,显示过滤器让wireshark只显示想看的数据包 Ethernet过滤器(第二层过滤器) ether host <> 抓取以太网流量的源或目的MAC地址(比如:ether host 00:00:5e:00:53:00) ether dst <> 抓取以太网流量的目的MAC地址 ether src<> 抓取以太网流
SpringSecurity过滤器链SecurityContextPersistenceFilter
sdaujsj1的博客
07-03 1096
SecurityContextPersistenceFilter SecurityContextPersistenceFilter是Springsecurity链中第二道防线,位于WebAsyncManagerIntegrationFilter之后,作用是为了存储SecurityContext而设计的。 SecurityContextPersistenceFilter主要做两件事: 当请求到来时,从HttpSession中获取SecurityContext并存入SecurityContextHolder中
参与评论 您还未登录,请先 登录 后发表或查看评论
spring security FilterSecurityInterceptor过滤器访问控制流程分析
a807719447的专栏
11-18 1036
FilterSecurityInterceptor.doFilter中调用了当前类的invoke(fi)方法参数fi为FilterInvocation(调用的对象内部封装了当前请求的一些列信息),该方法主要流程如下 public void invoke(FilterInvocation fi) throws IOException, ServletException { //判断当前请求的request不为null,FILTER_APPLIED这个属性限制 //了当前类型的过滤器仅执行一个,它结合obser
三个有用的过滤器
meazza10的专栏
04-21 208
一、使浏览器不缓存页面的过滤器 import javax.servlet.*; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * 用于的使 Browser 不缓存页面的过滤器 */ public class ForceNoCacheFilter implements Filter...
认识Wireshark之一 过滤器篇
热门推荐
hyderhan的专栏
12-02 1万+
wireshark应用
Filter(过滤器)常见应用(三)——权限管理系统(二)
mrdu_somefun的博客
10-14 488
Filter(过滤器)常见应用(三)——权限管理系统(二) 标签: Java-Web基础 2016-09-12 20:57 1157人阅读 评论(0) 收藏 举报  分类: Java Web基础(81)  版权声明:本文为博主原创文章,未经博主允许不得转载。 目录(?)[+] 由于开发一个简陋的权限管理系统,用一
Servlet 2.3过滤器编程
derstsea的专栏
08-31 250
摘要 Jason Hunter通过对一些自由而又实用的过滤器的研究以对新的servlet过滤器模型进行深入探讨。你将知道这些过滤器是如何工作以及你能用他们做什么。最后,Jason介绍了他自己为简化文件上传而做的多路请求过滤器。     在"Servlet 2.3: New Features Exposed,"中,我介绍了Servlet API 2.3中的变化并给出了一个
Servlet2.3规范详解:Web组件与引擎解析
"servlet2.3规范中文版.pdf" Servlet 2.3 规范是Java服务器端编程的重要组成部分,它定义了如何在Java平台上开发和部署Web应用程序。这个规范是基于Java 2企业版(J2EE)的,同时也与JSP 1.1、Java Naming and ...
servlet2.3规范中文版.rar
11-21
Servlet 2.3 规范是Java服务器端编程的重要指南,它定义了Servlet API的版本,这个API使得开发者...通过阅读“servlet2.3规范中文版”这本书,开发者可以深入理解Servlet的工作原理和最佳实践,提升Web应用开发能力。
Servlet2.3规范详解:基于Java的Web组件技术
"servlet2.3规范中文版.pdf" Servlet 2.3规范是Java Servlet技术的一个重要版本,它定义了如何在Web服务器或应用程序服务器中集成和管理Servlet。这个规范引入了对J2EE、JSP 1.1和JNDI的支持,使得Servlet可以更好...
JAVA三大有用的过滤器
liukai520312的专栏
08-20 434
一、使浏览器不缓存页面的过滤器 Java代码  import javax.servlet.*;   import javax.servlet.http.HttpServletResponse;   import java.io.IOException;     /**   * 用于的使 Browser 不缓存页面的过滤器   */  public class For
wireshark使用说明
newbix的专栏
09-06 1万+
第 1 章 介绍 1.1. 什么是Wireshark Wireshark 是网络包分析工具。网络包分析工具的主要作用是尝试捕获网络包, 并尝试显示包的尽可能详细的情况。 你可以把网络包分析工具当成是一种用来测量有什么东西从网线上进出的测量工具,就好像使电工用来测量进入电信的电量的电度表一样。(当然比那个更高级)  过去的此类工具要么是过于昂贵,要么是属于某人私有,或者是二者兼顾。 Wire
Wireshark基本介绍和学习TCP三次握手
weixin_34358092的博客
10-10 2336
之前写过一篇博客:用 Fiddler来调试HTTP,HTTPS。 这篇文章介绍另一个好用的抓包工具wireshark,用来获取网络数据封包,包括http,TCP,UDP,等网络协议包。 记得大学的时候就学习过TCP的三次握手协议,那时候只是知道,虽然在书上看过很多TCP和UDP的资料,但是从来没有真正见过这些数据包, 老是感觉在云上飘一样,学得不踏实。有了wiresha...
indispensable-tvosx64-3.14.0-javadoc.jar
09-13
indispensable-tvosx64-3.14.0-javadoc.jar
appsync-0.13.0-beta.jar
09-13
appsync-0.13.0-beta.jar
如官网下载不了的,直接下载安装包
最新发布
09-13
如官网下载不了的,直接下载安装包
pic-smaller.zip
09-13
这款图片压缩工具支持 JPG、PNG、WEBP、GIF、SVG 等多种格式,能够进行批量处理,并提供可调节的压缩选项。它完全在浏览器中运行,免费使用,无需注册。
chensheng913

博客等级

码龄21年
672
原创
48
点赞
231
收藏
553
粉丝
关注
私信

TA的精选

  • 新 Java程序员必须要了解的七个开源协议介绍

    11521 阅读

  • 新 JSP分页技术实现

    18868 阅读

  • 热 漫谈EJB

    291345 阅读

  • 热 同居的童话

    181664 阅读

  • 热 Struts原理与实践(三)

    52377 阅读

查看更多

2008年4篇
2007年7篇
2006年28篇
2005年281篇
2004年437篇

大家在看

  • Linux 中 exec 等冷门命令的执行逻辑探究 914
  • 鸿蒙 状态管理装饰器@State深度解析 535
  • Arduino 引脚常规输入功能全方位详细教程 505
  • Java字符串类对比解析 602
  • SpringBoot加载SQLite数据源 1324

分类专栏

  • BCB
    7篇
  • Java
    418篇
  • PB
    11篇
  • 乱弹
    110篇
  • 感悟人生
    12篇
  • 数据库开发应用
    115篇
  • 编程之道
    53篇

展开全部 收起

上一篇:
www.chinabbs.com 版主身份验证
下一篇:
JSP报表打印的一种简单解决方案

目录

展开全部

收起

相关专栏

AI人工智能与大数据应用开发架构

专栏

3 人学习

AI人工智能与大数据应用开发架构

SpringBoot一本通

专栏

26 人学习

涉及到spring boot使用过程中的配置优化、自动装配、模板使用、生命周期、嵌入式容器、全局异常处理、全局日志管理、异步任务、定时任务、redis缓存及session共享、fastdfs整合、SSE及websocket实现、消息队列、邮件发送等。

Java编程艺术:从入门到精通

专栏

0 人学习

结合《Programming in Java》一书,深入浅出讲解Java核心概念与实战技巧,助力编程能力稳步提升。

目录

展开全部

收起

上一篇:
www.chinabbs.com 版主身份验证
下一篇:
JSP报表打印的一种简单解决方案

分类专栏

  • BCB
    7篇
  • Java
    418篇
  • PB
    11篇
  • 乱弹
    110篇
  • 感悟人生
    12篇
  • 数据库开发应用
    115篇
  • 编程之道
    53篇

展开全部 收起

目录

评论
被折叠的  条评论 为什么被折叠? 到【灌水乐园】发言
查看更多评论
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值