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完成。