Servlet 2.3過濾器程式設計(二) (轉)

worldblog發表於2007-12-15
Servlet 2.3過濾器程式設計(二) (轉)[@more@]  2.3過濾器(二)

 :namespace prefix = o ns = "urn:schemas--com::office" />

過濾器

我們將看到的最後一個過濾器是處理多路/多型別資料的POST請求,該型別的請求能包含檔案上傳。每個多路/多型別資料POST請求包含所有引數和檔案,使用一種servlet不能識別的特別的格式。歷史上Servlet開發者使用第三方類來處理上傳,例如在我的com.oreilly.servlet包中的MultipartRequest和MultipartParser類。這裡我們將看到一種使用MultipartFilter的新方法來是處理這種請求更容易。該過濾器基於com.oreilly.servlet包下的parsers構建並已經被整合到該包中(參見world.com/javaworld/jw-06-2001/jw-0622-filters_p.html#res#resources">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;

 

  // Detene the 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 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接收打包過的請求以能透過其他方法來處理上傳的檔案。

 

.xml部署描述器用如下程式碼來新增此過濾器:

  multipartFilter

  com.oreilly.servlet.MultipartFilter

  <!--

 

  uploadDir

  /tmp

 

  --&gt

 

  multipartFilter

  /*

 

 

  uploadTest

 

 

  UploadTest

 

 

 

   uploadTest

 

 

  /uploadTest

 

 

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("");

  out.println("

UploadTest");

  out.println("

");

  out.println("

UploadTest

");

 

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

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

 

  out.println("

Request Parameters:

");

  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("

");

 

  // 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("

Files:

");

  out.println("

");

  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("

");

  }

  catch (Exception e) {

  out.println("

");

  e.printStackTrace(out);

  out.println("

");

  }

  }

 

  out.println("");

  }

}

 

servlet的前一半顯示了過濾器如何將引數資料毫無改變的傳送給接收的servlet。後半部分則顯示了一個servlet是如何將請求向下傳送給MultipartWrapper以獲得附加的檔案訪問方法。

 

一個此servlet的HTML例子如下:

What is your name?

What is your age?

Which file do you want to upload?

Any other file to upload?

 

這是可能的輸出:

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號釋出稿規範和 4.0 beta 5中,那是不確定的。實際上,如果你試圖用/servlet/UploadTest去訪問此servlet,你將注意到過濾並沒有正確工作,因為/servlet的呼叫將MultipartWrapper轉給Tomcat自己的特殊wrapper了。這允許引數能被正確解析,但檔案訪問方法卻不能正確工作。在Servlet API專家組的討論中,我們決定servlet容器不能對過濾器的wrapper做更多的包裝。這個servlet規範將被修改的更清楚。在Tomcat 4.0以後版本中將澄清這些規則。短期的辦法是在請求wrapper中使用getRequest()方法來“沿著”請求去找到這個隱藏的multipart wrapper。

 

從如下地址該WAR檔案:

 

過濾器能力

Servlet過濾器提供了一中強大的能力來控制請求的操作和響應的發生,提供新的servlet功能而不需要太多的程式碼。我希望透過這些已經向你展示使用過濾器的可能情況,並教給你一些關於如何更有效的使用新的過濾器機能的技巧。

 

感謝這些過濾器的作者以及其他對過濾器提供有用建議的的人:Amy Roh,Criag McClanahan,Serge Knystautas,以及OpenSymphony成員。

 

關於作者

  見原文

資源

  見原文

 

 

達人給指點斧正了,謝謝:)


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-993922/,如需轉載,請註明出處,否則將追究法律責任。

相關文章