Apache commons Fileupload简易教程


1 Apache Commons fileUpload 简易教程 Edit by:Alex Zhu Version:0.1 beta 目录 简介 ..........................................................................................................................................2 使用组件 FileUpload .............................................................................................................2 组件 FileUpload 是怎样工作的 ............................................................................................2 解析 request ...........................................................................................................................3 最简单的例子...........................................................................................................................3 实施更多的控制.......................................................................................................................3 How it works ..........................................................................................................................5 Servlets and Portlets ........................................................................................................6 Parsing the request ............................................................................................................6 The simplest case ........................................................................................................6 Exercising more control ............................................................................................7 Processing the uploaded items ........................................................................................8 Resource cleanup ..................................................................................................................9 Creating a DiskFileItemFactory ............................................................................10 Disabling cleanup of temporary files ................................................................11 Interaction with virus scanners ..................................................................................11 Watching progress ..............................................................................................................11 What's next ..........................................................................................................................13 2 简介 FileUpload 是 Apache commons 下面的一个子项目,用来实现 Java 环境下 的文件上传功能,与常见的 SmartUpload 齐名。 使用组件 FileUpload 可以通过许多种不同的方式使用组件 FileUpload,这个主要取决于你的应 用程序。在最简单的情况下,你可以调用单一的方法去解析这个 Servlet Request,然后处理选项列表,并应用到你的应用程序。另一方面,你可能决定 自定义 FileUpload,实现对选项列表种个别项完全控制。例如:你 可以将内容 注入到数据库。 这里,我们将描述组件 FileUpload 的基本原则,并讲解一些简单的、常用 的使用模式。FileUpload 自定制将在其他地方描述。 组件 FileUpload 依赖于 Commons IO组件,因此在继续之前,要确保在你的 工程 classpath 中有描述页中提到的相应版本。(这里 FileUpload 版本为: commons- fileupload-1.2.1,Commons IO 版本为:commons-io-1.4) 组件 FileUpload 是怎样工作的 上传的文件要求包括一个根据 RFC 1867(在 HTML 中基于表单的文件)编码 的选项列表清单。组件 FileUpload 可以解析这个请求,并给你的应用程序提供 一份独立上传的项目清单。无论每个项目背后如何执行都实现了 FileItem 接口。 这里将描述组件 FileUpload 库的普通 API,这些 API 比较简单。不过,对 于最终的实现,你可以参考最新的 API 流。 每一个文件项目都有一些属性,这些可能在你的应用程序中应用到。比如: 每一个项目有一个名称 name 和内容类型 content type,并提供了一个 InputStream 访问其数据。另一方面,你处理项目的方法可能有所不同,这个依 赖于是否这个项目是一个规则的表单域,即:这个数据是来自普通的表单文本, 还是普通的 HTML 域或是一个上传文件。在 FileItem 接口中提供了处理这些问题 的方法,可以更加方便的去访问这些数据。 组件 FileUpload 使用 FileItemFactory 工厂创建新的文件项目。这个给了 组件 FileUpload 很大的灵活性。这个工厂拥有怎样创建项目的最终控制权。工 厂执行过程中上传项目文件的临时数据可以存储在内存中或硬盘上。这个依赖于 上传项目的大小(即:数据的字节)。不过这种行为可以在你的应用程序中适当的 自定制。 3 解析 request 在实现上传项目之前,当然需要解析这个请求。确保这个请求的确是一个正 确的上传文件,组件 FileUpload 为了使这个判断简单,提供了一个静态的方法 去做这个事情。 // 检测我们是否一个文件上传的请求 boolean isMultipart = ServletFileUpload.isMultipartContent(request); 最简单的例子 最简单的使用情况如下: * 上传项目只要足够小,就应该将其保存在内存中。 * 较大的项目应该被写入到硬盘的临时文件中。 * 应该避免有非常大的上传项目。 * 设置项目默认的在内存中所占的空间,限制最大的上传请求,并设定 临时文件的位置。 处理这种情况下的请求非常的简单: // 创建磁盘工厂 FileItemFactory factory = new DiskFileItemFactory(); // 创建处理工具 ServletFileUpload upload = new ServletFileUpload(factory); // 解析 List items = upload.parseRequest(request); 这就是我们真正需要的全部代码。 处理的结果是生成了一个文件项目列表,每个文件项目实现一个 FileItem 接口。下面将介绍如何处理这些项目。 实施更多的控制 如果你的使用情况和上面描述的例子很接近,但是你需要在一点更多的控制 限定文件的大小或临时文件的存放位置。你可以很容易的自定义上传实例或文件 项目或两者的行为。下面例子展示了几种配置选项: // 创建磁盘工厂 DiskFileItemFactory factory = new DiskFileItemFactory(); // 设置参数 factory.setSizeThreshold(yourMaxMemorySize); factory.setRepository(yourTempDirectory); // 创建处理工具 ServletFileUpload upload = new ServletFileUpload(factory); // 指定单个上传文件的最大尺寸,单位:字节 upload.setFileSizeMax(yourSingleFileMaxSize); // 设置最大允许的尺寸, 上传多个文件的总尺寸 4 upload.setSizeMax(yourMaxRequestSize); // 解析 List items = upload.parseRequest(request); 当然,每一个配置处理方法都是独立于其他方法的,但是如果你想一次性配 置这个工厂,你可以使用工厂的另一个重载方法。像这样: DiskFileItemFactory factory = new DiskFileItemFactory( yourMaxMemorySize, yourTempDirectory); 如果你还需要更多的控制请求的解析,比如存储项目到其它地方(如:数据 库),你将需要看看 FileUpload 自定义(注:不知道为什么这里链接过去的页面什么也没 有)。 5 Using FileUpload FileUpload 文件上传 可以有许多不 同的使用方式,这取决于您的应用要 求。在最简单的情况下,你将调用一 个方法来解析 servlet 请求,然后以 适用于你的项目的方式来处理项目清 单 Items。或者另外的应用情况,你可 能会决定自定义文件上传,以完全控 制其中每个项目 Item 的存储方式,例 如,你可能决定将其流进一个数据库 中。 FileUpload can be used in a number of different ways, depending upon the requirements of your application. In the simplest case, you will call a single method to parse the servlet request, and then process the list of items as they apply to your application. At the other end of the scale, you might decide to customize FileUpload to take full control of the way in which individual items are stored; for example, you might decide to stream the content into a database. 在这里,我们将描述文件上传的基本 原则,并说明了一些简单的 - 也是最 常见的 - 使用模式。自定义的文件上 传描述别处。 Here, we will describe the basic principles of FileUpload, and illustrate some of the simpler - and most common - usage patterns. Customization of FileUpload is described elsewhere. 文件上传依赖通用 IO 类库,所以再继 续前,一定要在你的 classpath 中加 上依赖页提到的 IO 库版本。 FileUpload depends on Commons IO, so make sure you have the version mentioned on the dependencies page in your classpath before continuing. How it works A file upload request comprises an ordered list of items that are encoded according to RFC 1867, "Form-based File Upload in HTML". FileUpload can parse such a request and provide your application with a list of the individual uploaded items. Each such item implements the FileItem interface, regardless of its underlying implementation. This page describes the traditional API of the commons fileupload library. The traditional API is a convenient approach. However, for ultimate performance, you might prefer the faster Streaming API. Each file item has a number of properties that might be of interest for your application. For example, every item has a name and a content type, and can provide an InputStream to access its data. On the other hand, you may need to process items differently, depending upon whether the item is a regular form field - that is, the data came from an ordinary text box or similar HTML field - or an uploaded file. The FileItem interface provides the methods to make such a determination, and to access the data in the most appropriate manner. 6 FileUpload creates new file items using a FileItemFactory. This is what gives FileUpload most of its flexibility. The factory has ultimate control over how each item is created. The factory implementation that currently ships with FileUpload stores the item's data in memory or on disk, depending on the size of the item (i.e. bytes of data). However, this behavior can be customized to suit your application. Servlets and Portlets Starting with version 1.1, FileUpload supports file upload requests in both servlet and portlet environments. The usage is almost identical in the two environments, so the remainder of this document refers only to the servlet environment. If you are building a portlet application, the following are the two distinctions you should make as you read this document: • Where you see references to the ServletFileUpload class, substitute the PortletFileUpload class. • Where you see references to the HttpServletRequest class, substitute the ActionRequest class. Parsing the request Before you can work with the uploaded items, of course, you need to parse the request itself. Ensuring that the request is actually a file upload request is straightforward, but FileUpload makes it simplicity itself, by providing a static method to do just that. // Check that we have a file upload request boolean isMultipart = ServletFileUpload.isMultipartContent(request); Now we are ready to parse the request into its constituent items. The simplest case The simplest usage scenario is the following: • Uploaded items should be retained in memory as long as they are reasonably small. • Larger items should be written to a temporary file on disk. • Very large upload requests should not be permitted. 7 • The built-in defaults for the maximum size of an item to be retained in memory, the maximum permitted size of an upload request, and the location of temporary files are acceptable. Handling a request in this scenario couldn't be much simpler: // Create a factory for disk-based file items FileItemFactory factory = new DiskFileItemFactory(); // Create a new file upload handler ServletFileUpload upload = new ServletFileUpload(factory); // Parse the request List /* FileItem */ items = upload.parseRequest(request); That's all that's needed. Really! The result of the parse is a List of file items, each of which implements the FileItem interface. Processing these items is discussed below. Exercising more control If your usage scenario is close to the simplest case, described above, but you need a little more control, you can easily customize the behavior of the upload handler or the file item factory or both. The following example shows several configuration options: // Create a factory for disk-based file items DiskFileItemFactory factory = new DiskFileItemFactory(); // Set factory constraints factory.setSizeThreshold(yourMaxMemorySize); factory.setRepository(yourTempDirectory); // Create a new file upload handler ServletFileUpload upload = new ServletFileUpload(factory); // Set overall request size constraint upload.setSizeMax(yourMaxRequestSize); // Parse the request List /* FileItem */ items = upload.parseRequest(request); 8 Of course, each of the configuration methods is independent of the others, but if you want to configure the factory all at once, you can do that with an alternative constructor, like this: // Create a factory for disk-based file items DiskFileItemFactory factory = new DiskFileItemFactory( yourMaxMemorySize, yourTempDirectory); Should you need further control over the parsing of the request, such as storing the items elsewhere - for example, in a database - you will need to look into customizing FileUpload. Processing the uploaded items Once the parse has completed, you will have a List of file items that you need to process. In most cases, you will want to handle file uploads differently from regular form fields, so you might process the list like this: // Process the uploaded items Iterator iter = items.iterator(); while (iter.hasNext()) { FileItem item = (FileItem) iter.next(); if (item.isFormField()) { processFormField(item); } else { processUploadedFile(item); } } For a regular form field, you will most likely be interested only in the name of the item, and its String value. As you might expect, accessing these is very simple. // Process a regular form field if (item.isFormField()) { String name = item.getFieldName(); String value = item.getString(); ... } 9 For a file upload, there are several different things you might want to know before you process the content. Here is an example of some of the methods you might be interested in. // Process a file upload if (!item.isFormField()) { String fieldName = item.getFieldName(); String fileName = item.getName(); String contentType = item.getContentType(); boolean isInMemory = item.isInMemory(); long sizeInBytes = item.getSize(); ... } With uploaded files, you generally will not want to access them via memory, unless they are small, or unless you have no other alternative. Rather, you will want to process the content as a stream, or write the entire file to its ultimate location. FileUpload provides simple means of accomplishing both of these. // Process a file upload if (writeToFile) { File uploadedFile = new File(...); item.write(uploadedFile); } else { InputStream uploadedStream = item.getInputStream(); ... uploadedStream.close(); } Note that, in the default implementation of FileUpload, write() will attempt to rename the file to the specified destination, if the data is already in a temporary file. Actually copying the data is only done if the the rename fails, for some reason, or if the data was in memory. If you do need to access the uploaded data in memory, you need simply call the get() method to obtain the data as an array of bytes. // Process a file upload in memory byte[] data = item.get(); ... Resource cleanup 10 This section applies only, if you are using the DiskFileItem. In other words, it applies, if your uploaded files are written to temporary files before processing them. Such temporary files are deleted automatically, if they are no longer used (more precisely, if the corresponding instance of java.io.File is garbage collected. This is done silently by the org.apache.commons.io.FileCleaner class, which starts a reaper thread. This reaper thread should be stopped, if it is no longer needed. In a servlet environment, this is done by using a special servlet context listener, called FileCleanerCleanup. To do so, add a section like the following to your web.xml: ... org.apache.commons.fileupload.servlet.FileCleanerCleanup ... Creating a DiskFileItemFactory The FileCleanerCleanup provides an instance of org.apache.commons.io.FileCleaningTracker. This instance must be used when creating a org.apache.commons.fileupload.disk.DiskFileItemFactory. This should be done by calling a method like the following: public static DiskFileItemFactory newDiskFileItemFactory(ServletContext context, File repository) { FileCleaningTracker fileCleaningTracker = FileCleanerCleanup.getFileCleaningTracker(context); DiskFileItemFactory factory = new DiskFileItemFactory(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD, repository); factory.setFileCleaningTracker(fileCleaningTracker); return factory; } 11 Disabling cleanup of temporary files To disable tracking of temporary files, you may set the FileCleaningTracker to null. Consequently, created files will no longer be tracked. In particular, they will no longer be deleted automatically. Interaction with virus scanners Virus scanners running on the same system as the web container can cause some unexpected behaviours for applications using FileUpload. This section describes some of the behaviours that you might encounter, and provides some ideas for how to handle them. The default implementation of FileUpload will cause uploaded items above a certain size threshold to be written to disk. As soon as such a file is closed, any virus scanner on the system will wake up and inspect it, and potentially quarantine the file - that is, move it to a special location where it will not cause problems. This, of course, will be a surprise to the application developer, since the uploaded file item will no longer be available for processing. On the other hand, uploaded items below that same threshold will be held in memory, and therefore will not be seen by virus scanners. This allows for the possibility of a virus being retained in some form (although if it is ever written to disk, the virus scanner would locate and inspect it). One commonly used solution is to set aside one directory on the system into which all uploaded files will be placed, and to configure the virus scanner to ignore that directory. This ensures that files will not be ripped out from under the application, but then leaves responsibility for virus scanning up to the application developer. Scanning the uploaded files for viruses can then be performed by an external process, which might move clean or cleaned files to an "approved" location, or by integrating a virus scanner within the application itself. The details of configuring an external process or integrating virus scanning into an application are outside the scope of this document. Watching progress If you expect really large file uploads, then it would be nice to report to your users, how much is already received. Even HTML pages allow to implement a progress bar by returning a multipart/replace response, or something like that. 12 Watching the upload progress may be done by supplying a progress listener: //Create a progress listener ProgressListener progressListener = new ProgressListener(){ public void update(long pBytesRead, long pContentLength, int pItems) { System.out.println("We are currently reading item " + pItems); if (pContentLength == -1) { System.out.println("So far, " + pBytesRead + " bytes have been read."); } else { System.out.println("So far, " + pBytesRead + " of " + pContentLength + " bytes have been read."); } } }; upload.setProgressListener(progressListener); Do yourself a favour and implement your first progress listener just like the above, because it shows you a pitfall: The progress listener is called quite frequently. Depending on the servlet engine and other environment factory, it may be called for any network packet! In other words, your progress listener may become a performance problem! A typical solution might be, to reduce the progress listeners activity. For example, you might emit a message only, if the number of megabytes has changed: //Create a progress listener ProgressListener progressListener = new ProgressListener(){ private long megaBytes = -1; public void update(long pBytesRead, long pContentLength, int pItems) { long mBytes = pBytesRead / 1000000; if (megaBytes == mBytes) { return; } megaBytes = mBytes; System.out.println("We are currently reading item " + pItems); if (pContentLength == -1) { System.out.println("So far, " + pBytesRead + " bytes have been read."); } else { System.out.println("So far, " + pBytesRead + " of " + pContentLength + " bytes have been read."); 13 } } }; What's next Hopefully this page has provided you with a good idea of how to use FileUpload in your own applications. For more detail on the methods introduced here, as well as other available methods, you should refer to the JavaDocs. The usage described here should satisfy a large majority of file upload needs. However, should you have more complex requirements, FileUpload should still be able to help you, with it's flexible customization capabilities. 14 更简略的讲解 一.基本原理 FileUpload 组件将页面提交的所有元素(普通 form 表单域,如 text 和文件 域 file)都看作一样的 FileItem,这样上传页面提交的 request 请求也就是一 个 FileItem 的有序组合,FileUpload 组件可以解析该 request,并返回一个一 个的 FileItem。而对 每一个 FileItem,FileUpload 组件可以判断出它是普通 form 表单域还是文件 file 域,从而根据不同的类型,采取不同的操作--如果 是 表单域,就读出其值,如果是文件域,就保存文件到服务器硬盘上或者内存 中。 二.具体实现 对一个 HttpRequest 请求,我们要判断该请求是否是文件上传的请求 // Check that we have a file upload request boolean isMultipart = ServletFileUpload.isMultipartContent(request); 不过,个人觉得这个方法一般不需要,我们一般是在需要上传时才采用 fileupload 组件处理 request 请求的。 如果确实是文件上传的请求,我们如何解析该 request 呢? // Create a factory for disk-based file items FileItemFactory factory = new DiskFileItemFactory(); // Create a new file upload handler ServletFileUpload upload = new ServletFileUpload(factory); // Parse the request List /* FileItem */ items = upload.parseRequest(request); 至此我们已经的到了 FileItem 的 list,对每个 Item 的处理要考虑是标准的 form 表单域还是上传文件 file 域,然后做不同的处理,可以通过以下方式实现: // Process the uploaded items Iterator iter = items.iterator(); while (iter.hasNext()) { FileItem item = (FileItem) iter.next(); if (item.isFormField()) { processFormField(item); } else { processUploadedFile(item); } } 对于一个简单的 form 表单域,我们可以通过以下方法得到该域的相关信息: // Process a regular form field if (item.isFormField()) { String name = item.getFieldName(); String value = item.getString(); 15 ... } 而对于一个 upload file,我们则可以通过如下方式得到其相关信息: // Process a file upload if (!item.isFormField()) { String fieldName = item.getFieldName(); String fileName = item.getName(); String contentType = item.getContentType(); boolean isInMemory = item.isInMemory(); long sizeInBytes = item.getSize(); ... } 实际上,对于一个上传的文件,我们一般不会把它包存在内存中,除非它足 够小。我们一般是把它保存到硬盘上,使用以下方法就可以将上传的文件保存到 服务器硬盘上了: File uploadedFile = new File(...); item.write(uploadedFile); 好了,到了这里,fileupload 组件的基本 api 已经介绍完了,大家应该有点 轮廓了吧。 16 示例代码 <%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> Insert title here
first file:
second file:
third file:
处理代码 <%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> <%@ page import="org.apache.commons.fileupload.util.*,org.apache.commons.f ileupload.*,org.apache.commons.fileupload.servlet.*,java.io.*"%> Insert title here <% //Check that we have a file upload request boolean isMultipart = ServletFileUpload.isMultipartContent(request); //Create a new file upload handler ServletFileUpload upload = new ServletFileUpload(); // Parse the request FileItemIterator iter = upload.getItemIterator(request); 17 while (iter.hasNext()) { FileItemStream item = iter.next(); String name = item.getFieldName(); InputStream stream = item.openStream(); if (item.isFormField()) { out.println("Form field " + name + " with value " + Streams.asString(stream) + " detected."); } else { out.println("File field " + name + " with file name " + item.getName() + " detected."); // Process the input stream } } %> 18 Download 示例 <%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> Insert title here <%!java.util.Random rand = new java.util.Random(System.currentTimeMillis());%> download file: your file
处理 import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet implementation class DownloadServlet */ public class DownloadServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public DownloadServlet() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) 19 */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("application/x-msdownload"); String fileName = request.getParameter("fileName"); OutputStream os = response.getOutputStream(); String realContextPath = this.getServletContext().getRealPath("/"); System.out.println(realContextPath + "/upload/" + fileName); InputStream is = new BufferedInputStream(new FileInputStream(realContextPath + "/upload/" + fileName)); byte[] buffer = new byte[512]; int length = 0; while ((length = is.read(buffer)) > 0){ os.write(buffer, 0, length); } os.flush(); is.close(); } } 20 示例 <%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> upload employee info
21
Employee Name:
Employee Address:
Contact Number:
Employee Email ID:
Employee Image
处理结果 <%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> <%@ page import="java.util.List"%> <%@ page import="java.util.Iterator"%> <%@ page import="java.io.File"%> <%@ page import="org.apache.commons.fileupload.servlet.ServletFileUpload"%> <%@ page import="org.apache.commons.fileupload.disk.DiskFileItemFactory"%> <%@ page import="org.apache.commons.fileupload.*"%> Insert title here

Your Profile has been Uploaded

<%!String emp_name = ""; 22 String emp_c_number = ""; String emp_emailid = ""; String address1 = ""; String address2 = ""; int count1 = 0, count2 = 0, count3 = 0, count4 = 0, count5 = 0;%> <% boolean isMultipart = ServletFileUpload.isMultipartContent(request); if (!isMultipart) { } else { FileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); List items = null; try { items = upload.parseRequest(request); } catch (FileUploadException e) { e.printStackTrace(); } Iterator itr = items.iterator(); while (itr.hasNext()) { FileItem item = (FileItem) itr.next(); if (item.isFormField()) { String name = item.getFieldName(); String value = item.getString(); if (name.equals("emp_name")) { emp_name = value; count1 = 1; } if (name.equals("address1")) { address1 = value; count2 = 2; } if (name.equals("address2")) { address2 = value; count5 = 5; } if (name.equals("contact_number")) { emp_c_number = value; count3 = 3; } if (name.equals("email_id")) { count4 = 4; emp_emailid = value; } } else { try { String itemName = item.getName(); File savedFile = new File(config .getServletContext().getRealPath("/") + "images\\" + itemName); item.write(savedFile); %>
23
<% if (count1 == 1) out.println("
Name:" + emp_name); if (count2 == 2) out.println("
Addresss:" + address1); if (count5 == 5) out.println("
" + address2); if (count3 == 3) out.println("
Contact No" + emp_c_number); if (count4 == 4) out.println("
Email ID" + emp_emailid); } catch (Exception e) { e.printStackTrace(); } } } } %>
还剩22页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享pdf获得金币 ] 3 人已下载

下载pdf

pdf贡献者

yanguz123

贡献于2012-01-04

下载需要 10 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf