解析请求
在你能够与上传的项目,当然,你需要解析请求本身。确保请求实际上是一个文件上传的要求很简单,但文件上传使它本身就是简单的,通过提供一个静态方法来做到这一点。
/ /检查,我们有一个文件上传请求 boolean isMultipart = ServletFileUpload.isMultipartContent(request);
现在,我们已经准备好解析成其构成项目的要求。
最简单的例子
最简单的使用情况如下:
- 上传项目应保留,只要是合理的小内存。
- 较大的项目应写入到磁盘上的一个临时文件。
- 非常大的上传请求不应当允许。
- 内置的默认的最大规模的项目将保留在内存中,最大允许的大小上载的请求,临时文件的位置是可以接受的。
处理在这种情况下请求不能简单得多:
/ /创建一个磁盘工厂的文件项目 FileItemFactory factory = new DiskFileItemFactory(); / /创建一个新文件上传处理 ServletFileUpload上传=新ServletFileUpload(factory); / /解析请求 List /* FileItem */ items = upload.parseRequest(request);
这一切的需要。真正地!
该分析结果是 名单
文件的项目,每个项目都实现了 FileItem
接口。下文将讨论处理这些项目。
行使更多的控制
如果您的使用情况是接近最简单的情况,如上所述,但是你需要更多的控制权,可以轻松地自定义上传的处理程序或文件项目工厂或两种行为。下面的例子显示了几个配置选项:
/ /创建一个磁盘工厂的文件项目 DiskFileItemFactory factory = new DiskFileItemFactory(); / /设置工厂的限制 factory.setSizeThreshold(yourMaxMemorySize); factory.setRepository(yourTempDirectory); / /创建一个新文件上传处理 ServletFileUpload upload = new ServletFileUpload(factory); / /设置请求的大小限制的整体 upload.setSizeMax(yourMaxRequestSize); / /解析请求 List /* FileItem */ items = upload.parseRequest(request);
当然,在配置方法是相互独立的人,但如果你要配置一次工厂所有,你可以与另一种构造,像这样:
/ /创建一个磁盘工厂的文件项目 DiskFileItemFactory factory = new DiskFileItemFactory( yourMaxMemorySize, yourTempDirectory);
如果您需要,如存储在其他项目的要求,进一步控制分析, - 例如,在一个数据库中 - 你需要研究 定制 文件上传。
处理上载项目
一旦分析完成后,您将有一个 名单
项目的文件,您需要处理。在大多数情况下,您需要经常处理文件上传表单域不同,所以你可能会过程中,像这样的列表:
/ /处理上传的项目 Iterator iter = items.iterator(); while (iter.hasNext()) { FileItem item = (FileItem) iter.next(); if (item.isFormField()) { processFormField(item); } else { processUploadedFile(item); } }
对于一个普通窗体域,您很可能只在感兴趣的项目的名称,其 字符串
值。正如您可能期望,访问这些是非常简单的。
/ /处理普通表单字段 if (item.isFormField()) { String name = item.getFieldName(); String value = item.getString(); ... }
对于一个文件上传,有几种不同的东西你可能想知道您处理之前的内容。下面是一些方法,例如你可能感兴趣
/ /处理文件上传 if (!item.isFormField()) { String fieldName = item.getFieldName(); String fileName = item.getName(); String contentType = item.getContentType(); boolean isInMemory = item.isInMemory(); long sizeInBytes = item.getSize(); ... }
已上载文件,你一般不会希望通过内存访问他们,除非它们是小,或除非你有没有其他选择。相反,你将要处理作为流,或写入整个文件内容,其最终位置。文件上传完成提供了这两种简单的方法。
/ /处理文件上传 if (writeToFile) { File uploadedFile = new File(...); item.write(uploadedFile); } else { InputStream uploadedStream = item.getInputStream(); ... uploadedStream.close(); }
请注意,在文件上传的默认实现, 写()
将尝试重命名该文件到指定的目标,如果数据已经在临时文件。其实复制数据只是进行重命名,如果失败,出于某种原因,或者是在内存中的数据。
如果你需要访问内存中的上传数据,您需要简单地调用 获得()
方法来获得一个字节数组中的数据。
/ /处理内存中的文件上传 byte[] data = item.get(); ...
资源清理
本节仅适用,如果您使用的是 DiskFileItem 。换句话说,它适用,如果您上传的文件被写入处理前他们的临时文件。
这样的临时文件会被自动删除,如果它们不再被使用(更确切地说,如果相应的实例 java.io.File
被垃圾收集。这样做是无声的org.apache.commons.io.FileCleaner
类,它启动一个收割机线程。
这收割机线程应该停止,如果它不再需要。在一个servlet的环境,这是通过使用一个特殊的servlet上下文监听器,称为 FileCleanerCleanup 。为此,添加类似下面的部分你 web.xml文件
:
<web-app> ... <listener> <listener-class> org.apache.commons.fileupload.servlet.FileCleanerCleanup </listener-class> </listener> ... </web-app>
创建DiskFileItemFactory
该FileCleanerCleanup提供了一个实例 org.apache.commons.io.FileCleaningTracker
。此实例时,必须使用创建org.apache.commons.fileupload.disk.DiskFileItemFactory
。这项工作应通过调用一个类似下面的方法:
public static DiskFileItemFactory newDiskFileItemFactory(ServletContext context, File repository) { FileCleaningTracker fileCleaningTracker = FileCleanerCleanup.getFileCleaningTracker(context); return new DiskFileItemFactory(fileCleaningTracker, DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD, repository); }
互动病毒扫描
病毒扫描程序对Web容器的同一系统上运行的应用程序可能会导致某些使用文件上传意想不到的行为。本节描述的行为,您可能会遇到一些,并提供了如何处理它们的一些想法。
默认的文件上传的实施将造成一定规模以上的门槛上载项目被写入到磁盘。只要这样的文件被关闭,系统上的任何人觉醒,检查,病毒扫描,并可能检疫文件 - 也就是说,它移动到一个特殊的位置不会产生问题。当然,这将是一个以应用程序开发人员感到惊讶,因为上载文件的项目将不再用于处理。另一方面,低于相同的门槛上载项目将在内存中,因此不会受到病毒扫描可见。这使得对病毒的可能性某种形式保留下来(如果它虽然都写入磁盘,病毒扫描程序会找到并检查)。
一个常用的解决办法是搁置关于对所有上传的文件将被放置一个目录系统,并配置病毒扫描程序忽略该目录。这将确保文件将不会被欺骗的应用程序下进行,但后来离开扫描到应用软件的开发病毒的责任。扫描病毒上传的文件可以由一个外部进程,这可能会移动或清洗干净的文件“认可”的位置,或将其集成在应用程序本身就是一个病毒扫描。外部的配置过程或集成病毒扫描到应用程序的细节超出了本文的范围。
看着进展
如果你希望真正大文件上传,那么将是不错的报告给用户,有多少是已经收到。即使HTML网页允许执行返回一个多一个进度栏/取代反应,或类似的东西。
看着上传进度可采取通过提供一个进度监听器:
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);
你自己好和执行上面的一样你的第一个进展听众,因为这表明你的陷阱:进展侦听称为相当频繁。根据不同的servlet引擎和其他环境的工厂,可以要求任何网络数据包!换句话说,你的进步听众可能成为一个性能问题!一个典型的解决办法可能是,以减少听众活动的进展情况。例如,你可能只排放,如果兆字节数已更改的消息:
/ /创建一个过程侦听 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."); } } };
在此记录一下,最近比较郁闷,不知道为什么有时候就登陆不了javaeye,还有javaeye的编辑器,我怎么都不会用,还有那个附件上传的,字都不让传。。闹心。希望改进一下,不然我就要搬家了。为O(∩_∩)Ø哈!