** JavaWeb中的upload** <Excerpt in index | 首页摘要>
一个人如果活着没有梦想,那和咸鱼有什么区别?
<The rest of contents | 余下全文>
JavaWeb中Upload问题解决
使用multipart/form-data属性后无法获取参数
解决方案
通过js代码解决
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<form id="upload" name="upload" action="fileftp.jsp" method="post" ENCTYPE="multipart/form-data">
<input type="hidden" name="otherName" id="otherName" value="abcdefg">
<td nowrap>
<input type="file" id="file1" name="file1" value="" size="40" class="sbttn">
<input type="submit" value="upload" class="sbttn">
</td>
</form>
<script language="javascript">
function formSubmit(){
var action = "fileftp.jsp";
action += "?otherName=" + document.upload.otherName.value;
document.upload.action = action;
document.upload.submit();
}
</script>
通过修改服务器端代码。利用jar包
commons-fileupload-1.2.2.jar和commons-io-1.4.jar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17//创建工厂
//工厂类可以设置很多对上传文件的限制内容
DiskFileItemFactory factory = new DiskFileItemFactory();
//创建解析器
ServletFileUpload sfu = new ServletFileUpload(factory);
sfu.setSizeMax(intsize);//设置文件中的大小也可以设置单个文件的大小
//解析request
try{
List<FileItem> list = sfu.parseRequest(request);
for(FileItem fileitem : list){
if(fileitem.isFormField()){
//FileItem类型的对象里有一个方法isFormField(),可以判断表单项是表单域还是文件域
String name = fileitem.getFildName();
String value = fileitem.getString();
}
}
}commons-fileUpload.jar
1
2public DiskFileItemFactory()
public DiskFileItemFactory(int sizeThreshold, File repository)sizeThreshold:服务器内存,资源有限
限制:sizeThreshold临界值,600KB 上传的文件,如果小于600KB,则把接受到的整个文件放在内存中,程序直接从内存中读取,如果文件大于600KB,则把传过来的文件分成很多部分放在磁盘上的某个零时文件夹,程序需要文件时就去内存和临时文件夹里的临时文件中去读取
repository:配置临时文件夹的位置1
void setSizeThreshold(int sizeThreshold)
Apache文件上传组件在解析上传数据中的每个字段内容时,需要临时保存解析出的数据,以便在后面进行数据的进一步处理(保存在磁盘特定位置或插入数据库)。
因为Java虚拟机默认可以使用的内存空间时有限的,超出限制时将会抛出“java.lang.OutOfMemoryError”错误。
如果上传的文件很大,例如800M的文件,在内存中将无法临时保存该文件内容,Apache文件上传组件转而采用临时文件来保存这些数据;但如果上传文件的问价很小,例如600个子节的文件,显然将其直接保存在内存中性能会更好一些
sizeSizeThreshold方法用于设置是否将上传文件以临时问价的形式保存在磁盘的临界值(以子节为单位的int值),如果从没有调用该方法设置此临界值,将会采用系统的默认值10KB。对应的getSizeThreshold()方法来获取此临界值
1
void setRepository(File repository)
setRepositoryPath方法用于设置当上传文件尺寸大于setSizeThreshold方法设置的临界值时,将文件以临时文件形式保存在磁盘上的存放目录。有一个对应的获得临时文件夹的File getRespository()方法
注意:当没有调用此方法设置临时文件存储目录时,默认采用系统默认的临时文件路径,可以通过系统属性java.io.tmpdir 获取。如下代码:1
System.getProperty("java.io.tmpdir");
Tomcat服务器默认临时目录为“<tomcat安装目录>/temp/”
FileItem类的常用方法:
1
boolean isFormField()
isFormField方法用于判断FileItem类对象封装的数据是一个普通文本表单字段,还是一个文件表单字段,如果是普通表单字段则放回true,否则返回false。因此,可以使用该方法判断是否为普通表单域,还是文件上传域。
1
String getName()
getName方法用于获得文件上传字段中的文件名。
注意 IE或FireFox中获取的文件名是不一样的,IE中式绝对路径,FireFox中只是文件名
1
String getFieldName()
getFieldName方法用于返回表单标签name属性的值。如上例中<input type=”text” name=”column”>的value
1
void write(File file)
write方法用于将FileItem对象中保存的主体内容保存到某个指定的文件中。如果FileItem对象中的主体内容是保存在某个临时文件中,该方法顺利完成后,临时文件有可能会被清楚。该方法也可将普通表单字段内容写如多一个文件中,但它主要用途是将上传的文件内容保存在本地文件系统中。
1
String getString()
getString方法用于将FileItem对象中保存的数据流内容以一个字符串返回,它有两个重载的定义形式:
public java.lang.String getString()
public java.lang.String getString(java.lang.String encoding)
前者使用缺省的字符集编码将主体内容转换成字符串,后者使用参数指定的字符集编码将主体内容转换成字符串。如果在读取普通表单字段元素的内容是出现了中文乱码现象,请调用第二个getString方法,并为之传递正确的字符集编码名称。
1
String getContentType()
getContentType方法用于获得上传文件的类型,即表单字段元素描述头属性“Content-Type”的值,如果“image/jpeg”。如果FileItem类对象对应的是普通表单字段,该方法将返回null。
1
boolean isInMemory()
isInMemoory方法用来判断FileItem对象封装的数据内容是存储在内存中,还是存储在临时文件中,如果存储在内存中则返回true,否则返回false
1
void delete()
delete方法用来清空FileItem类对象中存放的主体内容,如果主体内容被保存在临时文件中,delete方法将删除该临时文件
尽管当FileItem对象被垃圾收集器收集时会自动清楚临时文件,但及时调用delete方法可以更早的清除临时文件,释放系统存储资源。另外,当系统出现异常时,仍然可能造成有的临时文件被永久保存在了硬盘中。
1
InputStream getInputStream()
以流的形式返回上传文件的数据内容
1
long getSize()
返回该上传文件的大小(以子节为单位)
上传文件注意项:
- 为保证服务器安全,上传问价应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下。
- 为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名。
- 为防止一个目录下出现太多文件,要使用hash算法打散存储。
- 要限制上传文件的最大值
- 要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。
基本思路
- 获取和创建保存文件的最终目录和临时目录
- 创建一个DiskFileItemFactory工厂
- 创建一个文件上传解析器
- 判断提交上来的数据是否是上传表单的数据,是不是Multipart编码方式ServletFileUpload.isMultipartContext(request)
- 使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List
集合 - 判断普通域还是文件域
- 将普通表单域的键值对显示出来
- 验证后缀的合法性
- 将文件流写入保存的目录中(生成新的文件名,避免一个目录中文件太多而生成新的存储目录)