1.解析servlet request,做出对应的响应。
2.文件的上传下载,就是操作IO的。故需要Conmmons io支持。
3.FileItem对上传的数据来源,进行了封装了,使得,我们可以进行统一的处理。那么每一个上传的数据源,就对应一个FileItem。FileItemFactory负责创建FileItem。工厂创建的FileItem,可以决定上传的数据存储的位置,在内存或者文件中,根据应用需要。
4.FileUpload可以应用在servlet and portlet environments.这两个环境中,但是这两个环境还是存在差异的。
Where you see references to the ServletFileUpload class, substitute the PortletFileUpload class. Where you see references to the HttpServletRequest class, substitute the ActionRequest class.
5.通过一个类静态方法,验证servlet request,是否是一个文件上传请求。
// Check that we have a file upload request boolean isMultipart = ServletFileUpload.isMultipartContent(request);
6.最简单的文件上传功能:
文件上传基本原则
@1.上传的资源合理的小,应该放置在内存中,
@2.比较大的资源应该放置在文件中,
@3.上传的每个文件有大小限制,上传的总的大小有限制,上传的临时路径需要指定
@4.过大的上传请求,是不被执行的。
上传代码:
// Create a factory for disk-based file items FileItemFactory factory = new DiskFileItemFactory(); // Configure a repository (to ensure a secure temp location is used) ServletContext servletContext = this.getServletConfig().getServletContext(); File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir"); factory.setRepository(repository); // Create a new file upload handler ServletFileUpload upload = new ServletFileUpload(factory); // Parse the request List<FileItem> items = upload.parseRequest(request);7.针对上述的文件上传,想再添加一些额外的要求,我们可以从upload handler or the file item factory or both这三者进行入手。譬如:
// 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);上述的配置,仅仅使用一次,使用完了,还得继续搜集,要 一劳永逸的方法就是:
// Create a factory for disk-based file items DiskFileItemFactory factory = new DiskFileItemFactory(yourMaxMemorySize, yourTempDirectory);除了,上述的外,我们还可自定义,文件的上传路径,譬如上传到数据库中。待续...
8.上述的方法中,我们得到了要保存的文件,那么要做的就是,保存这些文件。
// Process the uploaded items Iterator<FileItem> iter = items.iterator(); while (iter.hasNext()) { FileItem item = iter.next(); if (item.isFormField()) { processFormField(item); } else { processUploadedFile(item); } }
processFormField(item);这个方法可能是这样的:
// Process a regular form field
if (item.isFormField()) {
String name = item.getFieldName();
String value = item.getString();
...
}
而这个方法可能是这样的:
processUploadedFile(item);
// 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(); ... } 也可能是这样的:将文件保存到最终的某个地方或者是变成inputstream// Process a file upload if (writeToFile) { File uploadedFile = new File(...); item.write(uploadedFile); } else { InputStream uploadedStream = item.getInputStream(); ... uploadedStream.close(); }
如果,希望使用内存中的资源,那么可以使用:
// Process a file upload in memory byte[] data = item.get();9.类似 DiskFileItem,在文件上传中,产生的临时文件,是会在 java.io.File对象被回收时, org.apache.commons.io.FileCleaner实例,自动进行回收。自动回收的进行需要在webapp的web.xml中进行配置
<web-app> ... <listener> <listener-class> org.apache.commons.fileupload.servlet.FileCleanerCleanup </listener-class> </listener> ... </web-app>10.我们如何得到FileCleaner实例呢?我们可以通过如下方式获取:
The FileCleanerCleanup provides an instance of org.apache.commons.io.FileCleaningTracker
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; } //注意:FileCleaningTracker to null时,自动删除临时文件,就不会得到进行了。11.文件上传,往往会触发系统上的病毒扫描。病毒扫描时,往往会就文件移到沙箱中进行,但是,上传的文件由于持有特殊的引用,而病毒扫描软件无法获取,那么就会使得病毒潜在。这就需要额外的扫描程序进行了。这里也不是文件上传所能介绍的,我理解的也是有限的,请多多批评指教。
12.文件在上传的过程中,我们很希望可以看到上传的进度情况。
进度的获取,我们呢,通过一个匿名的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);但是,这个进度监听函数,可能成为你应用中的一个性能问题。因为,监听每隔一定时间,会重复调用,那么就会带来性能问题。
常用的方法就是,监听函数,不要进行的太活跃。
//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."); } } };更加复杂代码的文件上传,需要结合其JavaDoc完成。