Java Web开发人员可以使用Apache文件上传组件来接收浏览器上传的文件该组件由多个类共同组成但是对于使用该组件来编写文件上传功能的Java Web开发人员来说只需要了解和使用其中的三个类DiskFileUploadFileItem和FileUploadException这三个类全部位于monsfileupload包中
DiskFileUpload类
DiskFileUpload类是Apache文件上传组件的核心类应用程序开发人员通过这个类来与Apache文件上传组件进行交互但现在Apache建议使用ServletFileUpload类两个类的方法类似下面介绍DiskFileUpload类中的几个常用的重要方法
.setSizeMax方法
setSizeMax方法用于设置请求消息实体内容的最大允许大小以防止客户端故意通过上传特大的文件来塞满服务器端的存储空间单位为字节其完整语法定义如下
public void setSizeMax(long sizeMax)
如果请求消息中的实体内容的大小超过了setSizeMax方法的设置值该方法将会抛出FileUploadException异常
.setSizeThreshold方法
Apache文件上传组件在解析和处理上传数据中的每个字段内容时需要临时保存解析出的数据因为Java虚拟机默认可以使用的内存空间是有限的(笔者测试不大于M)超出限制时将会发生javalangOutOfMemoryError错误如果上传的文件很大例如上传M的文件在内存中将无法保存该文件内容Apache文件上传组件将用临时文件来保存这些数据但如果上传的文件很小例如上传个字节的文件显然将其直接保存在内存中更加有效setSizeThreshold方法用于设置是否使用临时文件保存解析出的数据的那个临界值该方法传入的参数的单位是字节其完整语法定义如下
public void setSizeThreshold(int sizeThreshold)
setRepositoryPath方法
setRepositoryPath方法用于设置setSizeThreshold方法中提到的临时文件的存放目录这里要求使用绝对路径其完整语法定义如下
public void setRepositoryPath(String repositoryPath)
如果不设置存放路径那么临时文件将被储存在javaiotmpdir这个JVM环境属性所指定的目录中tomcat 将这个属性设置为了<tomcat安装目录>/temp/目录
parseRequest方法
parseRequest 方法是DiskFileUpload类的重要方法它是对HTTP请求消息进行解析的入口方法如果请求消息中的实体内容的类型不是multipart/formdata该方法将抛出FileUploadException异常parseRequest 方法解析出FORM表单中的每个字段的数据并将它们分别包装成独立的FileItem对象然后将这些FileItem对象加入进一个List类型的集合对象中返回parseRequest 方法的完整语法定义如下
public List parseRequest(HttpServletRequest req)
parseRequest 方法还有一个重载方法该方法集中处理上述所有方法的功能其完整语法定义如下
parseRequest(HttpServletRequest reqint sizeThresholdlong sizeMax
String path)
这两个parseRequest方法都会抛出FileUploadException异常
isMultipartContent方法
isMultipartContent方法方法用于判断请求消息中的内容是否是multipart/formdata类型是则返回true否则返回falseisMultipartContent方法是一个静态方法不用创建DiskFileUpload类的实例对象即可被调用其完整语法定义如下
public static final boolean isMultipartContent(HttpServletRequest req)
setHeaderEncoding方法
由于浏览器在提交FORM表单时会将普通表单中填写的文本内容传递给服务器对于文件上传字段除了传递原始的文件内容外还要传递其文件路径名等信息如后面的图所示不管FORM表单采用的是application/xwwwformurlencoded编码还是multipart/formdata编码它们仅仅是将各个FORM表单字段元素内容组织到一起的一种格式而这些内容又是由某种字符集编码来表示的关于浏览器采用何种字符集来编码FORM表单字段中的内容请参看笔者编着的《深入体验java Web开发内幕——核心基础》一书中的第的讲解multipart/formdata类型的表单为表单字段内容选择字符集编码的原理和方式与application/xwwwformurlencoded类型的表单是相同的FORM表单中填写的文本内容和文件上传字段中的文件路径名在内存中就是它们的某种字符集编码的字节数组形式Apache文件上传组件在读取这些内容时必须知道它们所采用的字符集编码才能将它们转换成正确的字符文本返回
对于浏览器上传给WEB服务器的各个表单字段的描述头内容Apache文件上传组件都需要将它们转换成字符串形式返回setHeaderEncoding 方法用于设置转换时所使用的字符集编码其原理与笔者编着的《深入体验java Web开发内幕——核心基础》一书中的第节讲解的ServletRequestsetCharacterEncoding方法相同setHeaderEncoding 方法的完整语法定义如下
public void setHeaderEncoding(String encoding)
其中encoding参数用于指定将各个表单字段的描述头内容转换成字符串时所使用的字符集编码
注意如果读者在使用Apache文件上传组件时遇到了中文字符的乱码问题一般都是没有正确调用setHeaderEncoding方法的原因
FileItem类
FileItem类用来封装单个表单字段元素的数据一个表单字段元素对应一个FileItem对象通过调用FileItem对象的方法可以获得相关表单字段元素的数据FileItem是一个接口在应用程序中使用的实际上是该接口一个实现类该实现类的名称并不重要程序可以采用FileItem接口类型来对它进行引用和访问为了便于讲解这里将FileItem实现类称之为FileItem类FileItem类还实现了Serializable接口以支持序列化操作
对于multipart/formdata类型的FORM表单浏览器上传的实体内容中的每个表单字段元素的数据之间用字段分隔界线进行分割两个分隔界线间的内容称为一个分区每个分区中的内容可以被看作两部分一部分是对表单字段元素进行描述的描述头另外一部是表单字段元素的主体内容如图所示
图
主体部分有两种可能性要么是用户填写的表单内容要么是文件内容FileItem类对象实际上就是对图中的一个分区的数据进行封装的对象它内部用了两个成员变量来分别存储描述头和主体内容其中保存主体内容的变量是一个输出流类型的对象当主体内容的大小小于DiskFileUploadsetSizeThreshold方法设置的临界值大小时这个流对象关联到一片内存主体内容将会被保存在内存中当主体内容的数据超过DiskFileUploadsetSizeThreshold方法设置的临界值大小时这个流对象关联到硬盘上的一个临时文件主体内容将被保存到该临时文件中临时文件的存储目录由DiskFileUploadsetRepositoryPath方法设置临时文件名的格式为upload_(八位或八位以上的数字)tmp这种形式FileItem类内部提供了维护临时文件名中的数值不重复的机制以保证了临时文件名的唯一性当应用程序将主体内容保存到一个指定的文件中时或者在FileItem对象被垃圾回收器回收时或者Java虚拟机结束时Apache文件上传组件都会尝试删除临时文件以尽量保证临时文件能被及时清除
下面介绍FileItem类中的几个常用的方法
isFormField方法
isFormField方法用于判断FileItem类对象封装的数据是否属于一个普通表单字段还是属于一个文件表单字段如果是普通表单字段则返回true否则返回false该方法的完整语法定义如下
public boolean isFormField()
getName方法
getName方法用于获得文件上传字段中的文件名对于图中的第三个分区所示的描述头getName方法返回的结果为字符串C:\bggif如果FileItem类对象对应的是普通表单字段getName方法将返回null即使用户没有通过网页表单中的文件字段传递任何文件但只要设置了文件表单字段的name属性浏览器也会将文件字段的信息传递给服务器只是文件名和文件内容部分都为空但这个表单字段仍然对应一个FileItem对象此时getName方法返回结果为空字符串读者在调用Apache文件上传组件时要注意考虑这个情况getName方法的完整语法定义如下
public String getName()
注意如果用户使用Windows系统上传文件浏览器将传递该文件的完整路径如果用户使用Linux或者Unix系统上传文件浏览器将只传递该文件的名称部分
.getFieldName方法
getFieldName方法用于返回表单字段元素的name属性值也就是返回图中的各个描述头部分中的name属性值例如name=p中的pgetFieldName方法的完整语法定义如下
public String getFieldName()
write方法
write方法用于将FileItem对象中保存的主体内容保存到某个指定的文件中如果FileItem对象中的主体内容是保存在某个临时文件中该方法顺利完成后临时文件有可能会被清除该方法也可将普通表单字段内容写入到一个文件中但它主要用途是将上传的文件内容保存在本地文件系统中其完整语法定义如下
public void write(File file)
.getString方法
getString方法用于将FileItem对象中保存的主体内容作为一个字符串返回它有两个重载的定义形式
public javalangString getString()
public javalangString getString(javalangString encoding)
throws javaioUnsupportedEncodingException
前者使用缺省的字符集编码将主体内容转换成字符串后者使用参数指定的字符集编码将主体内容转换成字符串如果在读取普通表单字段元素的内容时出现了中文乱码现象请调用第二个getString方法并为之传递正确的字符集编码名称
getContentType方法
getContentType 方法用于获得上传文件的类型对于图中的第三个分区所示的描述头getContentType方法返回的结果为字符串image/gif即ContentType字段的值部分如果FileItem类对象对应的是普通表单字段该方法将返回nullgetContentType 方法的完整语法定义如下
public String getContentType()
isInMemory方法
isInMemory方法用来判断FileItem类对象封装的主体内容是存储在内存中还是存储在临时文件中如果存储在内存中则返回true否则返回false其完整语法定义如下
public boolean isInMemory()
delete方法
delete方法用来清空FileItem类对象中存放的主体内容如果主体内容被保存在临时文件中delete方法将删除该临时文件尽管Apache组件使用了多种方式来尽量及时清理临时文件但系统出现异常时仍有可能造成有的临时文件被永久保存在了硬盘中在有些情况下可以调用这个方法来及时删除临时文件其完整语法定义如下
public void delete()
FileUploadException类
在文件上传过程中可能发生各种各样的异常例如网络中断数据丢失等等为了对不同异常进行合适的处理Apache文件上传组件还开发了四个异常类其中FileUploadException是其他异常类的父类其他几个类只是被间接调用的底层类对于Apache组件调用人员来说只需对FileUploadException异常类进行捕获和处理即可
ServletRequestContext
ServletRequestContext类提供访问request的方法实现RequestContext接口