本作品采用知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议进行许可。
当客户端浏览器指定enctype为multipart/form-data提交表单时,HTTP服务器上与该请求对应的servlet(Servlet类或JSP网页)将无法通过request对象的getParameter()方法取得表单域的属性值。如果对HTTP协议熟悉的话,我们可以对multipart/form-data数据流进行分析,取出其中有用的信息。但这样做完全没有必要,Apache的Commons FileUpload程序包已经替我们完成了这项复杂的工作。
基本用法
FileUpload API提供了两种核心处理类:PortletFileUpload和ServletFileUpload,本文不对PortletFileUpload做详细描述。ServletFileUpload类有一个判断Content-Type是否为multipart/form-data的方法。同时提供了两种读取multipart/form-data数据的方式:数据流读取方式和临时文件读取方式。
判断是否是multipart/form-data
利用ServletFileUpload类的静态方法可以判断一个request的Content-Type是否是multipart/form-data。例:
数据流读取方式
通过无参构造器生成的ServletFileUpload对象使用的是数据流读取方式,可通过getItemIterator()方法取得每一个表单域的数据。如:
数据流读取方式是一种一次性的读取方式。一方面,upload对象只能对request的数据做一次性分析。也就是说,上文第5行只在第一次调用时有效。另一方面,分析数据只能读取一次,第二次读取时数据不存在。也就是说,上文第5行取到的FileItemIterator对象只能遍历一次,第二次遍历该对象时就无法取到数据了。
临时文件读取方式
通过有参构造器生成的ServletFileUpload对象使用的是临时文件读取方式,可通过parseRequest()方法取得表单域数据列表。如:
同样,upload对象只能对request的数据做一次性分析。但与数据流读取方式相对应的是,临时文件读取方式中解析出来的数据被缓存到缓冲文件中,可对缓存数据多次读取,并且在必要的情况下可以修改缓存的内容。
FileUpload API出于下面的考虑实现了临时文件读取方式
- 如果上传内容比较小,则将其直接放入到内存中进行管理;
- 较大的上传内容将保存到磁盘上的一个临时文件夹中;
- 非常大的上传内容将被忽视。
默认情况下,FileUpload对数据大小的要求是:
- 小于10K的数据直接放到内存中管理;
- 大于10K的数据保存到系统临时目录中(系统临时目录是System.getProperty("java.io.tmpdir")的返回值);
- 所有的数据都不被忽视,即使这个数据非常大。
如何改变这些默认值呢?
如何控制FileUpload
作为核心应用对象,ServletFileUpload可以设置以下属性:
sizeMax
限制整个multipart/form-data数据的字节大小。默认值-1,表示无限制。
fileSizeMax
限制每个文件表单域中数据的字节大小。默认值-1,表示无限制。
headerEncoding
指定每个multipart头部信息的编码方式。默认为NULL,如果该值为NULL,则使用request中的characterEncoding值,如果characterEncoding为NULL,则使用系统默认的字符集编码方式。
设置属性的样例如下:
如果FileUpload使用临时文件读取方式,还可以为工厂类设置以下属性:
sizeThreshold
限制将文件表单域中的数据保存到内存的临界字节大小。默认为10K字节长度,数据小于10K字节则直接保存在内存中;数据大于10K字节则保存在临时文件夹中。
repository
临时文件夹的位置。默认为System.getProperty("java.io.tmpdir")的返回值。
例如改变临时文件夹的位置到“C:/tmp”的方法如下:
附1:FileUpload附加信息
官方网站
http://commons.apache.org/fileupload/
核心JAR包
commons-fileupload-1.2.1.jar
依赖JAR包
commons-io-1.4.jar
附2:HTTP请求数据结构
当客户端浏览器使用GBK编码提交了下面这样一个表单时...
一个数据内容如下的HTTP请求将会发送到HTTP服务器上。
POST /test/hello.html HTTP/1.1
Referer: http://localhost:9000/test/
Accept-Language: zh-cn
Content-Type: multipart/form-data; boundary=---------------------------7d91f4b304fc
Accept-Encoding: gzip, deflate
Host: localhost:9000
Content-Length: 301
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: JSESSIONID=763D1C03A83AE30CCFBA88F42465F598
-----------------------------7d91f4b304fc
Content-Disposition: form-data; name="name"
中国
-----------------------------7d91f4b304fc
Content-Disposition: form-data; name="file"; filename="C:/test.txt"
Content-Type: text/plain
这是测试文档的内容
-----------------------------7d91f4b304fc--[end]
每一个multipart的头部信息用红字表示;其编码所用的字符集是表单所在网页在浏览器上显示时所使用的字符集。
如果multipart是一般表单域,如上例中的name表单域,其内容一般为字符串,字符串编码所用的字符集与multipart的头部信息相同。
如果multipart是文件表单域,如上例中的file表单域,其内容为文件数据的二进制表现形成,内容格式由multipart的头部信息指定。