servlet文件上传下载
?用户上传头像、上传图片、邮件上传附件等
??? 文件上传表单和普通表单有两个区别
??? 1) 需要文件上传字段? <input type=”file” />
??? 2) form 表单的 enctype 属性需要指定为 multipart/form-data
??? 在 Servlet 中通过 request.getInputStream 获得表单上传数据,会发现数据是分段发送的
由于自己写程序解析有难度,我们可以使用Apache 开发的开源组件Commons-fileupload
需要导入 jar 包Commons-fileupload 和Commons-io
?
// 1. 创建工厂类
DiskFileItemFactory factory = new DiskFileItemFactory();
// 2. 创建FileUpload对象
ServletFileUpload upload = new ServletFileUpload(factory);
// 3. 判断是否是上传表单
boolean b = upload.isMultipartContent(request);
if(!b) {
??? // 不是文件上传
request.setAttribute("message", "对不起,不是文件上传表单!");
request.getRequestDispatcher("/message.jsp").forward(request, response);
??? return;
}
// 是文件上传表单
// 4. 解析request,获得FileItem项
List<FileItem> fileitems = upload.parseRequest(request);
// 5. 遍历集合
for(FileItem item : fileitems) {
??? // 判断是不是普通字段
if(item.isFormField()) {
??? String name = item.getFieldName();
??? String value = item.getString();
??? // 手工的转换了
??? value = new String(value.getBytes("iso-8859-1"),"utf-8");
??? System.out.println(name + "=" + value);
} else {
??? // 文件上传字段
??? // 获得文件名
??? String filename = item.getName();
??? System.out.println(filename);
??? filename = filename.substring(filename.lastIndexOf("\")+1);
???
??? System.out.println(filename);
??? // 创建文件
??? ServletContext context = getServletContext();
??? String dir = context.getRealPath("WEN-INF/upload");
??? File file = new File(dir, filename);
??? file.createNewFile();
???
??? // 获得流,读取数据写入文件
??? InputStream in = item.getInputStream();
??? FileOutputStream fos = new FileOutputStream(file);
???
??? int len;
??? byte[] buffer = new byte[1024];
??? while((len=in.read(buffer))>0)
?????? fos.write(buffer,0,len);
??? fos.close();
??? in.close();
??? item.delete();??? // 删除临时文件
}
?
?
??? 1) 文件名中文乱码问题,解决办法: 告诉文件上传组件以什么编码方式来解码文件名
?????? ServletUpload.setCharacterEncoding(“utf-8”);
?????? request. setCharacterEncoding(“utf-8”);
????
??? 2) 普通字段中文乱码问题
?????? fileitem.getString(“utf-8”);??????
?
??? 对于大文件不能缓存在内存,需要缓存到硬盘,为了方便管理,我们需要设置临时文件存放目录
??? // 设置临时文件的存放位置
factory.setRepository(new File("d:/temp"));
?
??? 文件上传完毕需要删除临时文件,否则会导致服务器存在两份上传文件
// 注意,需要先将流进行关闭,否则会导致临时文件无法删除
out.close();
in.close();
// 删除临时文件
fileitem.delete();
?
??? 1) 目录需要隐藏,禁止外界直接访问
??? 2) 文件名需要保证不重复
??? 3) 文件应该分目录存放
?
??? 需要实现对文件上传进度的监听,需要给FileUpload 对象添加 ProgressListener
??? 在upload方法中对与进度相关的数据进行处理
??? upload.setProgressListener(new ProgressListener() {
??? long num = 0;
??? public void update(long bytesRead, long contentLength, int items) {
??????
??? ??? ??? long progress = bytesRead*100/contentLength;
?????? ??? if(progress==num)
?????????? ??? return;
?????? ??? num = progress;
?????? ??? System.out.println("上传进度:" + progress + "%");
??????
??? ??? //? request.getSession().setAttribute("progress", progress);
??? ??? }
??? });
?
??? 实验:?
??? 1) 使用 iframe 发送请求, 请求一个Servlet, 在Servlet 中返回响应,发送自增的num
?????? 此时会发现 iframe 会不停第想Servlet发送请求
??? 2) 点击文件上传按钮后,iframe立刻停止刷新,直至上传完毕页面跳转至新页面
??? 3)为了观察实验结果,将form 的 target 指定为 iframe, UploadServlet回送上传完毕的结果
??? 4) 出现上述问题的原因,浏览器不支持多线程同时访问服务器只能同时发送一个请求,
?????? 这样的访问方式为同步访问
??? 5) 要在文件上传的同时在iframe中实现进度访问,就需要ie浏览器与服务器进行异步交互
?????? 此时就需要 XMLHttpRequest 对象
?????? 在javascript中可以直接使用XMLHttpRequest 对象与服务器进行异步通信
?????? 获得XmlHttpRequest 对象的方式有两种
?????? ie7以上版本
?????? var xhr = null;
?????? if(window.XMLHttpRequest)
?????????? xhr = new XMLHttpRequest();
?????? ie7以下版本
?????? if(window.ActiveXObject)
?????????? xhr = new ActiveXObject(“Microsoft.XMLHTTP”);
??????
?????? 获得对象后需要调用open方法输入请求地址
?????? 注意请求方式, 地址的输入, 并且需要设置为true 指定异步访问该地址
?????? xhr.open(“get”,”/upload/servlet/UploadServlet”, false)
??????
?????? // 调用send 方法发送请求,post方式需要发送消息体,get方式则不用直接传入null值
?????? xhr.send(null);
??????
?????? // 访问 responseText 属性获得 Servlet 回送的数据
?????? document.write(xhr.responseText);
?
??? 设置缓冲区大小,字节为单位,默认为10K,一般不用修改
??? factory.setSizeThreshold(1000);
??? 设置临时文件存放目录
??? factory.setRepository(file);
?
??? 判断是否为文件上传表单
??? boolean b = upload.isMultipartContent(request);
?? 解析request对象
?? List<FileItem> list = upload.parseRequest(request);
?? 设置上传文件的最大值
??? setFileSizeMax(long?fileSizeMax)
??? 设置上传文件总量的最大值
??? setSizeMax(long?sizeMax)
??? 设置编码格式
??? setHeaderEncoding(java.lang.String?encoding)
??? 注册进度监听器
??? setProgressListener(ProgressListener?pListener)
?
??? 获得表单字段的属性名
??? item.getFieldName();
??? 获得普通字段的值
??? item.getString(charsetName)
??? 获得文件上传字段的文件名
??? item.getName()
??? 获得文件上传的流
??? item.getInputStream()
??
?
1 楼 debbykindom 2011-10-25 好,王力宏