客户端
相对于FTP文件上传,Web文件上传速度慢一些,但使用方便,不需要客户端,而且权限比FTP容易控制。
Web文件上传采用POST方式,上传文件需要设置FORM的entype属性为multipart/form-data。由于上传的文件会比较大,需要设置该参数指定浏览器使用二进制上传。否则enctype属性默认为application/x-www-form-urlencoded,浏览器将使用ASCII向服务器发送数据,导致失败。
服务器端
上传文件时浏览器以二进制方式发送数据,因此Servlet不能简单通过HttpServletRequest的getParameter()方法来获取文件域及文本域的内容。必须根据HTTP协议所规定的格式解析浏览器提交的Request。
可以使用很多类库来完成解析,如SMartUpload和Apache Commons Fileupload。SmartUpload是商业类库,解析Request过程中数据存放在内存里,速度较快,但上传较大文件时会发生内存溢出。Apache Commons Fileupload 是免费的开源类库,Struts 里就集成了这个类库来实现文件上传。
DiskFileUpload diskFileUpload = new DiskFileUpload();
List<FileItem> list = diskFileUpload.parseRequest(request);
for(FileItem fileItem: list)
if(fileItem.isFormFileld())..//文本域
else if("file1".equals(fileItem.getFieldName()))
//服务器端文件,放在upload文件夹下
file1 = new File(this.getServletContext().getRealPath(),remoteFile.getName());
...
上传文件时数据将以二进制形式提交,因此Servlet用request.getParameter()等方式获取提交的文本内容,可以使用Commons-upload解析二进制数据。
带进度条的文件上传
原理:
服务器在处理上传文件的同时,将上传进度的信息例如文件总长度、以上传多少、传输速率等写入Session中。客户端浏览器利用Ajax技术再新开一个独立的线程从Session中获取上传进度信息,并实时显示。Ajax技术能够不刷新页面获取服务器数据。Session可看做是服务器内存,可用于存放少量的客户信息。
--上传监听器
commons-fileupload支持上传监听,只需要实现一个监听器,并把它添加到上传组件上即可。监听器需要实现它的ProgressListener接口。
public class UploadListener implements ProgressListener {
private UploadStatus status; //记录上传信息的Java Bean
public UploadListener(UploadStatus status){this.status = status;}
public void update(long bytesRead, long contentLength, int items){
//上传组件会调用该方法
status.setBuytesRead(bytesRead); //已读取的数据长度
status.setContentLength(contentLength);
status.setItems(items); //正在保存第几个文件
}}
添加了该监听器后,上传组件在上传文件时,会不断地回调该方法,回传这些数据。利用这些数据,就可以计算出文件上传的进度,用进度条实时显示出来。
处理文件上传的Servlet:ProgressUploadServlet,监听上传过程需要为ServletFileUpload安装一个监听器,然后把存有上传进度信息的UploadStatus对象放进Session。上传文件使用的是Post方法。
读取上传进度:以POST方式访问ProgressUploadServlet,会执行上传代码;如果以GET方式访问,会执行读取上传进度的代码。
显示上传进度
上传文件时,如果不对表单做特别处理,提交表单后会转到另一个页面,造成页面的刷新。而且新页面显示前,浏览器会因等待而显示白屏。因此需要对表单进行处理,使提交表单后原页面内容不变,并显示进度条,指导上传完成。方法是更改Form的target属性。
<form action="servlet/ProgressUploadServlet" methos="post"
enctype="multipart/form-data" target="upload_iframe" οnsubmit="showStatus();">