一、 Introduction
在web系统中,文件上传和下载是非常常用和重要的功能。使用servlet实现客户端上传和下载文件的功能,需要导入commons-fileupload-1.X.X-bin和commons-io-2.X两个jar包。
二、 FileUpload
1. 上传表单jsp页面
<body>
<div class="frame">
<div class="body">
<div class="upAndDown">
<form action="${root }/fileUpload"method="post" enctype="multipart/form-data">
请选择一个文件:<input type="file" name="file"value="上传文件" /><br />
<input type="submit"value="提交" />
</form>
</div>
</div>
</div>
</body>
2. 编写Servlet处理文件上传
使用到的关键类或接口
1) DiskFileItemFactory
org.apache.commons.fileupload.disk
Class DiskFileItemFactory
org.apache.commons.fileupload.disk.DiskFileItemFactory
All Implemented Interfaces:FileItemFactory
Direct Known Subclasses:DefaultFileItemFactory
public class DiskFileItemFactory
extends Object
implements FileItemFactory
The default FileItemFactory implementation. This implementationcreates FileItem instances which keep their content either inmemory, for smaller items, or in a temporary file on disk, for larger items.The size threshold, above which content will be stored on disk, isconfigurable, as is the directory in which temporary files will be created.
If not otherwise configured, the defaultconfiguration values are as follows:
Size threshold is 10KB.
Repository is the system default tempdirectory, as returned by System.getProperty("java.io.tmpdir").
NOTE: Files are created in the system defaulttemp directory with predictable names. This means that a local attacker withwrite access to that directory can perform a TOUTOC attack to replace anyuploaded file with a file of the attackers choice. The implications of thiswill depend on how the uploaded file is used but could be significant. Whenusing this implementation in an environment with local, untrusted users, setRepository(File) MUST be used toconfigure a repository location that is not publicly writable. In a Servletcontainer the location identified by the ServletContext attribute javax.servlet.context.tempdir may be used.
Temporary files, which are created forfile items, should be deleted later on. The best way to do this is usinga FileCleaningTracker, which you can set on the DiskFileItemFactory. However, if you do use such a tracker, thenyou must consider the following: Temporary files are automatically deleted assoon as they are no longer needed. (More precisely, when the correspondinginstance of File isgarbage collected.) This is done by the so-called reaper thread, which isstarted and stopped automatically by the FileCleaningTrackerwhen there are files to be tracked. It mightmake sense to terminate that thread, for example, if your web application ends.See the section on "Resource cleanup" in the users guide ofcommons-fileupload.
Since:FileUpload 1.1
Version:$Id: DiskFileItemFactory.java 15647882014-02-05 14:36:41Z markt $
2) ServletFileUpload
org.apache.commons.fileupload.servlet
Class ServletFileUpload
org.apache.commons.fileupload.FileUploadBase
org.apache.commons.fileupload.FileUpload
org.apache.commons.fileupload.servlet.ServletFileUpload
public class ServletFileUpload
extends FileUpload
High level API for processing fileuploads.
This class handles multiple files per singleHTML widget, sent using multipart/mixed encoding type, as specified by RFC 1867. UseparseRequest(HttpServletRequest) toacquire a list of FileItems associated with a given HTML widget.
How the data for individual parts isstored is determined by the factory used to create them; a given part may be inmemory, on disk, or somewhere else.
Version:$Id: ServletFileUpload.java 14559492013-03-13 14:14:44Z simonetripodi $
构造器
ServletFileUpload
(FileItemFactory fileItemFactory)
Constructs aninstance of this class which uses the supplied factory to create FileItem
instances.
重要方法
List<FileItem> | parseRequest(HttpServletRequest request) |
3) FileItem
org.apache.commons.fileupload
Interface FileItem
All Superinterfaces:
FileItemHeadersSupport, Serializable
All Known Implementing Classes:
DefaultFileItem, DiskFileItem
public interface FileItem
extends Serializable, FileItemHeadersSupport
This class represents a file or form itemthat was received within a multipart/form-data POST request.
After retrieving an instance of this classfrom a FileUpload instance(see #parseRequest(javax.servlet.http.HttpServletRequest)), you mayeither request all contents of the file at once using get() or request an InputStream with getInputStream() and process the filewithout attempting to load it into memory, which may come handy with largefiles.
While this interface does not extend javax.activation.DataSource per se (to avoid a seldom useddependency), several of the defined methods are specifically defined with thesame signatures as methods in that interface. This allows an implementation ofthis interface to also implement javax.activation.DataSource with minimal additional work.
Since:1.3 additionally implementsFileItemHeadersSupport
Version:$Id: FileItem.java 1454690 2013-03-0912:08:48Z simonetripodi $
getFieldName() | |
getInputStream() | |
getName() | |
getOutputStream() | |
boolean | isFormField() |
void | write(File file) |
protected void doGet(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException {
DiskFileItemFactory fileFactory=new DiskFileItemFactory();
ServletFileUpload fileUp=new ServletFileUpload(fileFactory);
fileUp.setHeaderEncoding("utf-8");
String message="";
try {
List<FileItem> flist=fileUp.parseRequest(request);
for(FileItem fileItem:flist){
if(fileItem.isFormField()){
String name=fileItem.getFieldName();
String value=fileItem.getString("utf-8");
System.out.println(name+"--"+value);
}else{
String fileName=fileItem.getName();
System.out.println(fileName);
fileName=UUID.randomUUID().toString()+"_"+fileName;
String filePath=this.getServletContext().getRealPath("/upload");
System.out.println(filePath);
File file=new File(filePath,fileName);
try {
fileItem.write(file);
message="上传成功。";
} catch (Exception e) {
e.printStackTrace();
}
}
}
} catch (FileUploadException e) {
message="上传失败,请重试";
e.printStackTrace();
}
request.setAttribute("message", message);
request.getRequestDispatcher("/fileUpload.jsp").forward(request,response);
}
其中设置文件名编码的代码:fileUp.setHeaderEncoding("utf-8");
设置普通表单输入框值的编码的代码:Stringvalue=fileItem.getString("utf-8");
三、 FileDownload
文件下载,将web系统中的文件资源提供给用户进行下载。文件下载有2种形式。
1. 使用超链接显示可显示性质的内容,如txt文件,图片文件,压缩文件等,然后另存为。非真正意义的下载。以中文命名的文件名可能被编码,导致下载失效。
2. 使用servlet完成下载。
步骤:
1) 浏览器发送请求给服务器
2) 服务器加载用户请求下载的文件
3) 通知浏览器以下载的方式请求资源
4) 使用IO流,将数据发送到客户端
例子:
Jsp页面
<a href="${root }/download?fileName=1.jpg" >1.jpg</a>
处理文件下载的servlet
protected voiddoGet(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException {
String fileName=request.getParameter("fileName");
System.out.println(fileName);
String filePath=this.getServletContext().getRealPath("/upload");
File file=new File(filePath,fileName);
//设置媒体文件的格式
response.setContentType(this.getServletContext().getMimeType(fileName));
//处理文件下载名称的编码问题
String userAgent=request.getHeader("User-Agent");
if(userAgent.contains("Firefox")){
//火狐浏览器的处理方式
BASE64Encoder base64Encoder = new BASE64Encoder();
fileName = "=?utf-8?B?" + base64Encoder.encode(fileName.getBytes("utf-8")) + "?=";
}else{
//其他浏览器的处理方式
fileName = URLEncoder.encode(fileName,"utf-8");
}
//设置要下载的文件的名称
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
//使用IO流传送数据
//创建输入流
FileInputStream inputStream=new FileInputStream(file);
//创建输出流
ServletOutputStream sos=response.getOutputStream();
byte[] b=newbyte[1024];
int len=0;
while((len=inputStream.read(b))!=-1){
sos.write(b,0,len);
}
inputStream.close();
}
注意例子中处理文件的中文字符名称的编码的方法。