使用Apache Commons Fileupload 文件上传组件需要两个类库文件:
1) commons-fileupload-1.2.2.jar
2) commons-io-1.4.jar
在浏览器中输入http://commons.apache.org/fileupload/ 打开Apache Commons Fileupload 文件上传组件主页面,在 Downloading 栏目中点击任意一个版本号后面的“here”超级链接,可以打开当前最新版本的 Apache Commons Fileupload 文件上传组件下载页面,(2010-08-28为止的可下载最新版本是1.2.2版)。也可以直接输入http://commons.apache.org/fileupload/download_fileupload.cgi 打开最新版本下载页面。
在当前最新版本的下载页面,提供二进制可执行版本(Binares)和源程序版本(Source)两种文件的下载,每一种文件都有两种压缩格式:
1) .zip,适用windows 操作系统
2) .tar.gz,适用 linux 和 unix 操作系统
我们这里选择下载 commons-fileupload-1.3.3-bin.zip 文件。解压后得到如下目录结构:
commons-fileupload-1.3.3 (根目录)
----- commons-fileupload-1.3.3.jar (我们要用的二进制类库)
-----site (包括Apache Commons Fileupload 组件站点所有页面文件)
----- apidocs (API文档目录,API文档链接可以在下面的首页中找到,也可以直接打开此目录,点击index.html打开API文档)
----- index.html(站点首页)
在浏览器中输入http://commons.apache.org/io/ 打开 Apache Commons IO 的主页,点击左侧菜单选项中的 Download 超级链接,打开当前最新版本下载页面(http://commons.apache.org/io/download_io.cgi),选择下载 commons-io-1.4-bin.zip 文件,解压缩在根目录中即可得到 commons-io-1.4.jar 。
到这里,我们就准备好了文件上传所需要的需要类库文件了。
一般在用Servlet处理表单元素时,表单元素都是一些简单的文本,Servlet很容易用Request.getParameter()就可以处理。但是当表单不止包含一些简单的文本,比如有上传文件域时,Servlet直接从HttpServletRequest对象中解析出复合表单的每一个子部分仍然是一项非常复杂的工作.
用户在客户端提交请求的方式:
有两种方式的POST方式请求:
1)Content-Type的值为:application/x-www-form-urlencoded
该方式提交普通表单组件,对应file组件只提交文件名----默认
2)Content-Type的值为:multipart/form-date
改方式可以提交帮普通表单组件和file组件,对于file组件不仅提交文件名,还提交文件内容数据流,
如果表单中包含file组件,必须使用该方式提交,否则不会上传文件内容数据流
upload
package cn.hncu.servlet;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.List;
import java.util.UUID;
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.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
public class UploadServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//防止用户在地址栏,以get方式提交请求。
response.setContentType("text/html;charset=utf-8");
PrintWriter pw = response.getWriter();
pw.println("文件上传出来不支持get方式提交");
pw.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
request.setCharacterEncoding("utf-8"); //只对上传的文件名有效,对普通表单的编码无效
//防黑2:防止用户以POST1的方式请求
//法1:手动利用底层原理来实现
// String type=request.getContentType();
// if(!type.contains("multipart/form-date")){
// out.println("文件上传不支持POST1方式提交");
// }
//法2:用apache文件上传工具提供的功能来实现
//获取src下的目录--ClassLoader 获取WebRoot下的目录---ServletContext
String path=getServletContext().getRealPath("/uploads");
File dir=new File("e:/a"); //临时文件存放目录
//创建一个文件上传句柄---可以对factory进行设置属性
FileItemFactory factory=new DiskFileItemFactory(1024*8,dir); //设置缓存的大小和位置
/**
* org.apache.commons.fileupload.servlet.ServletFileUpload类是
* Apache文件上传组件处理文件上传的核心高级类
* (所谓高级就是不需要管底层实现,暴露给用户的简单易用的接口)。
*/
ServletFileUpload upload=new ServletFileUpload(factory); //根据参数指定的FileItemFactory对象来创建
upload.setFileSizeMax(124*1024*5); //设置每个文件最大为5M
upload.setSizeMax(1024*1024*8); //设置全部文件容量为8M
//进度监听
upload.setProgressListener(new ProgressListener() {
/**
* 1.pBytesRead 已经接收了多少字节
* 2.pContentLength 总共多少字节
* 3.pItems 第几个文件(序号从1开始)
*/
@Override
public void update(long pBytesRead, long pContentLength, int pItems) {
double d=pBytesRead*100/pContentLength; //得出的是百分数形式的进度值
//实战时,要吧d值存入到session--表示一个用户,以让前端进度条的Ajax来读取
System.out.println(d+"%");
}
});
FileItem fi=null;
//利用upload工具吧request中的数据解析出来,结果为List
try {
List list=upload.parseRequest(request);
for(FileItem fileItem:list){
fi=fileItem;
if(fileItem.isFormField()){//普通表单组件
// System.out.println("普通表单组件"+fileItem.getName());
//解决普通表单组件的乱码问题
String desc=fileItem.getString("utf-8"); //以指定编码来接收desc编辑框上传的参数
// String desc=fileItem.getString();
System.out.println("desc:"+desc);
}else{//file组件
String fileName=fileItem.getName();
System.out.println("file表单组件:"+fileName); //这里是返回file组件提交的文件名
//由于服务器磁盘中存储的资源文件名不能包含中文,
//因此要把文件名特殊处理一下(用UUid来代替),
//同时我们在引入“打散目录技术”
String ext=fileName.substring(fileName.lastIndexOf("."));
String uuid=UUID.randomUUID().toString().replace("-", "");
fileName=uuid+ext;
/**
* 引入“打散目录技术”:
*/
String dir1=Integer.toHexString(fileName.hashCode() & 0xf);
String dir2=Integer.toHexString((fileName.hashCode() & 0xf0)>>4);
fileName=dir1+"/"+dir2+"/"+fileName;
InputStream in = fileItem.getInputStream(); //上传文件的输入流
//可以手动写代码进行流拷贝
//这里使用appache的工具,更加方便
FileUtils.copyInputStreamToFile(in, new File(path+"/"+fileName));
// File file=new File(path+"/"+fileName);
// File dirFile=file.getParentFile();
// if(!dirFile.exists()){
// dirFile.mkdir();
// }
// fileItem.write(file);
}
}
} catch (FileUploadException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}finally{
fi.delete(); //删除临时文件
}
}
}