jsp文件上传大多采用采用开源项目来简化处理,这里列出常用的两个jar包的实现,并进行比较,说明他们的优缺点和应该注意的问题。
Commons FileUpload,可以在http://jakarta.apache.org/commons/fileupload/下载,这个包需要Commons IO的支持,可以在http://jakarta.apache.org/commons/io/下载
com.oreilly.servlet,可以在http://www.servlets.com/cos/下载
Commons FileUpload提供三种文件上传处理方式,DiskFileUpload、ServletFileUpload和PortletFileUpload三种方式,其中DiskFileUpload已经在javadoc下已经被标记为过期的方法,建议用ServletFileUpload代替,而PortletFileUpload需要配合portlet-api来使用,所以这里我们只介绍ServletFileUpload,并且这个也是最常用的。
com.oreilly.servlet也提供了三种文件上传的处理方式,MultipartWrapper、MultipartRequest和MultipartParser三种方式,其中MultipartWrapper和MultipartRequest的用法基本相同,并且没有MultipartRequest提供的操作多,所以这里介绍MultipartRequest,MultipartParser和前两者有些不同,可以用来处理某些特殊情况,例如表单中有两个同名的文件上传选择框。
我们暂时称三面三种文件上传方式分别为:ServletFileUpload方式(MultipartTestServlet)、MultipartRequest方式(MultipartTestServlet2)、MultipartParser方式(MultipartTestServlet3)
代码如下:
test.html
<%
@ page language
=
"
java
"
import
=
"
java.util.*
"
contentType
=
"
text/html;charset=gbk
"
pageEncoding
=
"
gbk
"
%>
<
html
>
<
body
>
<
form
action
="MultipartTestServlet"
enctype
="multipart/form-data"
method
="post"
>
<
input
type
="text"
name
="username"
/><
br
/>
<
input
type
="file"
name
="myfile"
/><
br
/>
<
input
type
="file"
name
="myfile"
/><
br
/>
<
input
type
="submit"
/>
</
form
>
<
br
/><
br
/><
br
/><
br
/>
<
form
action
="MultipartTestServlet2"
enctype
="multipart/form-data"
method
="post"
>
<
input
type
="text"
name
="username"
/><
br
/>
<
input
type
="file"
name
="myfile"
/><
br
/>
<
input
type
="file"
name
="myfile"
/><
br
/>
<
input
type
="submit"
/>
</
form
>
<
br
/><
br
/><
br
/><
br
/>
<
form
action
="MultipartTestServlet3"
enctype
="multipart/form-data"
method
="post"
>
<
input
type
="text"
name
="username"
/><
br
/>
<
input
type
="file"
name
="myfile"
/><
br
/>
<
input
type
="file"
name
="myfile"
/><
br
/>
<
input
type
="submit"
/>
</
form
>
</
body
>
</
html
>
MultipartTestServlet.java
package
com.bug.servlet;
import
java.io.File;
import
java.io.IOException;
import
java.util.ArrayList;
import
java.util.Iterator;
import
java.util.List;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
org.apache.commons.fileupload.FileItem;
import
org.apache.commons.fileupload.FileUpload;
import
org.apache.commons.fileupload.FileUploadException;
import
org.apache.commons.fileupload.RequestContext;
import
org.apache.commons.fileupload.disk.DiskFileItemFactory;
import
org.apache.commons.fileupload.servlet.ServletFileUpload;
import
org.apache.commons.fileupload.servlet.ServletRequestContext;
public
class
MultipartTestServlet
extends
HttpServlet
{
public
MultipartTestServlet()
{
super
();
}
public
void
doPost(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException
{
request.setCharacterEncoding(
"
gbk
"
);
RequestContext requestContext
=
new
ServletRequestContext(request);
if
(FileUpload.isMultipartContent(requestContext))
{
DiskFileItemFactory factory
=
new
DiskFileItemFactory();
factory.setRepository(
new
File(
"
c:/tmp/
"
));
ServletFileUpload upload
=
new
ServletFileUpload(factory);
//
upload.setHeaderEncoding("gbk");
upload.setSizeMax(
2000000
);
List items
=
new
ArrayList();
try
{
items
=
upload.parseRequest(request);
}
catch
(FileUploadException e1)
{
System.out.println(
"
文件上传发生错误
"
+
e1.getMessage());
}
Iterator it
=
items.iterator();
while
(it.hasNext())
{
FileItem fileItem
=
(FileItem) it.next();
if
(fileItem.isFormField())
{
System.out.println(fileItem.getFieldName()
+
"
"
+
fileItem.getName()
+
"
"
+
new
String(fileItem.getString().getBytes(
"
iso8859-1
"
),
"
gbk
"
));
}
else
{
System.out.println(fileItem.getFieldName()
+
"
"
+
fileItem.getName()
+
"
"
+
fileItem.isInMemory()
+
"
"
+
fileItem.getContentType()
+
"
"
+
fileItem.getSize());
if
(fileItem.getName()
!=
null
&&
fileItem.getSize()
!=
0
)
{
File fullFile
=
new
File(fileItem.getName());
File newFile
=
new
File(
"
c:/temp/
"
+
fullFile.getName());
try
{
fileItem.write(newFile);
}
catch
(Exception e)
{
e.printStackTrace();
}
}
else
{
System.out.println(
"
文件没有选择 或 文件内容为空
"
);
}
}
}
}
}
}
MultipartTestServlet2.java
package
com.bug.servlet;
import
java.io.IOException;
import
java.util.Enumeration;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
com.oreilly.servlet.MultipartRequest;
import
com.oreilly.servlet.multipart.DefaultFileRenamePolicy;
public
class
MultipartTestServlet2
extends
HttpServlet
{
public
MultipartTestServlet2()
{
super
();
}
public
void
doPost(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException
{
//
request.setCharacterEncoding("gbk"); 不起作用
System.out.println(
"
start
"
);
MultipartRequest multi
=
new
MultipartRequest(request,
"
c:/tmp/
"
,
2
*
1024
*
1024
,
"
gbk
"
,
new
DefaultFileRenamePolicy());
System.out.println(
"
start
"
);
Enumeration filesName
=
multi.getFileNames();
Enumeration paramsName
=
multi.getParameterNames();
while
(paramsName.hasMoreElements())
{
String paramName
=
(String) paramsName.nextElement();
System.out.println(multi.getParameter(paramName));
}
while
(filesName.hasMoreElements())
{
String fileName
=
(String) filesName.nextElement();
System.out.println(multi.getFilesystemName(fileName)
+
"
"
+
multi.getOriginalFileName(fileName)
+
"
"
+
multi.getContentType(fileName)
+
"
"
);
if
(multi.getFilesystemName(fileName)
!=
null
&&
!
multi.getFilesystemName(fileName).equals(
""
))
System.out.println(multi.getFile(fileName).toURI());
}
}
}
MultipartTestServlet3.java
package
com.bug.servlet;
import
java.io.File;
import
java.io.IOException;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
com.oreilly.servlet.multipart.FilePart;
import
com.oreilly.servlet.multipart.MultipartParser;
import
com.oreilly.servlet.multipart.ParamPart;
import
com.oreilly.servlet.multipart.Part;
public
class
MultipartTestServlet3
extends
HttpServlet
{
public
MultipartTestServlet3()
{
super
();
}
public
void
doPost(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException
{
MultipartParser mp
=
new
MultipartParser(request,
2
*
1024
*
1024
,
false
,
false
,
"
gbk
"
);
Part part;
while
((part
=
mp.readNextPart())
!=
null
)
{
String name
=
part.getName();
if
(part.isParam())
{
ParamPart paramPart
=
(ParamPart) part;
String value
=
paramPart.getStringValue();
System.out.println(
"
param: name=
"
+
name
+
"
; value=
"
+
value);
}
else
if
(part.isFile())
{
//
it's a file part
FilePart filePart
=
(FilePart) part;
String fileName
=
filePart.getFileName();
if
(fileName
!=
null
)
{
long
size
=
filePart.writeTo(
new
File(
"
c:/tmp/
"
));
System.out.println(
"
file: name=
"
+
name
+
"
; fileName=
"
+
fileName
+
"
, filePath=
"
+
filePart.getFilePath()
+
"
, contentType=
"
+
filePart.getContentType()
+
"
, size=
"
+
size);
}
else
{
System.out.println(
"
file: name=
"
+
name
+
"
; EMPTY
"
);
}
System.out.flush();
}
}
}
}
web.xml中加入
<
servlet
>
<
servlet-name
>
MultipartTestServlet
</
servlet-name
>
<
servlet-class
>
com.bug.servlet.MultipartTestServlet
</
servlet-class
>
</
servlet
>
<
servlet
>
<
servlet-name
>
MultipartTestServlet2
</
servlet-name
>
<
servlet-class
>
com.bug.servlet.MultipartTestServlet2
</
servlet-class
>
</
servlet
>
<
servlet
>
<
servlet-name
>
MultipartTestServlet3
</
servlet-name
>
<
servlet-class
>
com.bug.servlet.MultipartTestServlet3
</
servlet-class
>
</
servlet
>
<
servlet-mapping
>
<
servlet-name
>
MultipartTestServlet
</
servlet-name
>
<
url-pattern
>
/MultipartTestServlet
</
url-pattern
>
</
servlet-mapping
>
<
servlet-mapping
>
<
servlet-name
>
MultipartTestServlet2
</
servlet-name
>
<
url-pattern
>
/MultipartTestServlet2
</
url-pattern
>
</
servlet-mapping
>
<
servlet-mapping
>
<
servlet-name
>
MultipartTestServlet3
</
servlet-name
>
<
url-pattern
>
/MultipartTestServlet3
</
url-pattern
>
</
servlet-mapping
>
问题1、中文问题:
三种凡是都可以通过自己的方法来设置encoding为gbk开处理和解决中文问题,包括初始化的时候传入gbk作为参数,或是是初始化后通过setEncoding的方式来实现。
另外ServletFileUpload方式也可以通过request.setCharacterEncoding("gbk");的方式来实现,而其它两种方式不支持这种方式。
问题2、文件大小限制
ServletFileUpload方式可以设置文件大小限制,也可以不用设置,例子中的upload.setSizeMax(2000000)就可以注释掉。如果设置upload.setSizeMax(-1),表明不限制上传的大小。文档中没有指明默认的限制的多少,我在不设置的情况下上传了一个9M的东西,可以上传,估计默认是不限制大小的。
而MultipartRequest方式和MultipartParser方式是必须设置文件的上传文件的大小限制的,如果不设置,默认是1M的大小限制。
问题3、文件上传发生错误
如果文件上传过程中发生任何错误,或者是文件的大小超出了范围,系统都将抛出错误。
ServletFileUpload方式在upload.parseRequest(request)时抛出错误
MultipartRequest方式在new MultipartRequest(。。。)时抛出错误
MultipartParser方式在new MultipartParser(。。。)时抛出错误
问题4、上传同名文件时,他们保存到临时目录是的冲突问题
ServletFileUpload方式,不会有冲突,系统会把上传得文件按照一定的规则重新命名,保证不会冲突
MultipartParser方式,会产生冲突,系统会把文件按照上传时的文件名,保存到临时目录下,如果两个用会同时上传文件名相同的文件,那么就可能会产生冲突,一方把另一方的临时文件给替换了。
MultipartRequest方式,在初始化时如果提供了一个名称转换策略,就不会有冲突,如果不提桶,就会有冲突。在上面的例子中我们提供了一个new DefaultFileRenamePolicy()保证了文件名不会有冲突发生。
问题5:表单中有两个同名的文件上传选择框,就像我们例子中的myfile一样,每个表单中有两个name=“myfile”的上传框
ServletFileUpload方式,可以处理,可以分别得到他们各自的文件,
MultipartRequest方式,不可以处理,会发生冲突,会有一个上传框的文件覆盖了另外一个。
MultipartParser方式,可以处理,可以分别得到他们各自的文件,
备注:
代码比较乱,主要是为了说明他们间的区别。他们的详细地使用说明还是要参考他的javadoc和domo。
参考:
1、http://www.servlets.com/cos/#classes
2、http://jakarta.apache.org/commons/fileupload/apidocs/index.html
3、http://jakarta.apache.org/commons/fileupload/using.html
4、http://www.onjava.com/pub/a/onjava/2003/06/25/commons.html?page=3