Bootstrap

基于FileUpload组件实现文件上传进度条的显示

  技术背景
   文件上传是JaveWeb开发者经常遇到的一个功能,目前文件上传的技术也是五花八门,这其中Apache旗下的commons-fileupload组件是使用比较广泛的一个文件上传的开源组件,基于commons-fileupload实现文件上传操作简单,并且commons-fileupload还提供了文件获得文件上传进度的接口,基于此,开发者就可以在页面上实时动态的显示文件上传的进度,很大程度提高用户的体验。
·  技术分析
       文件上传的三要素
                1.表单的提交方式必须为POST方式
                2.表单中提供文件项
                3.将表单的enctype设置为multipart/form-data
       文件上传的步骤
                1.创建磁盘文件工厂对象
                2.创建核心的解析类对象
                3.设置监听文件上传进度的监听器,以便获得文件上传的进度
                4.解析请求,获得表单项的集合对象
                5.遍历表单项的集合 
                6.判断当前的表单项是否是文件项
                   6.1.如果是普通文本项,获得参数的名称和值
                   6.2.如果是文件项,获取文件内容,使用流写入到服务器磁盘中
·   进度条功能分析
页面上动态变化的进度条其实是一个具有背景色的div块,让这个div块的宽度随着文件上传的进度的多少而变化就是进度条。这其中要解决的问题是如何实时获得文件上传的进度,并且页面在文件没有上传结束前不能跳转。显然,此时要从服务器获得文件上传的进度必须使用异步请求的方式。服务器端可以将当前文件上传的进度放置在Session域中,前台间隔一段时间通过Ajax异步的方式从服务器端的Session中获得文件上传的进度,并更新div的宽度。

HTML代码
[HTML]  纯文本查看  复制代码
?
01
02
03
04
05
06
07
08
09
10
< body >
<!-- 进度条的DIV -->
< div id = "div1" style = "background-color: red;height: 20px;width: 0" ></ div >
<!-- 表单 -->
< form action = "${pageContext.request.contextPath }/FileUploadServlet" method = "post" enctype = "multipart/form-data" >
[font=宋体]文件描述[/font]:< input type = "text" name = "desc" >< br />
[font=宋体]文件[/font]:< input type = "file" name = "file" >< br />
< input type = "submit" value = "提交" >
</ form >
</ body >


Javascript代码
[JavaScript]  纯文本查看  复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
<script type= "text/javascript" src= "${pageContext.request.contextPath }/js/jquery-1.8.3.js" ></script>
<script type= "text/javascript" >
$( function (){
     $( "#div1" ).css( "width" , "0" );
     setInterval( "showProgress()" ,10);
});
 
//显示文件上传的进度
function showProgress(){
     $.get( "${pageContext.request.contextPath}/ShowFileUploadProgress" , function (data){
          $( "#div1" ).css( "width" ,data);
          })
}
</script>


Java代码
FileUploadServlet.java
[Java]  纯文本查看  复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.NumberFormat;
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.FileUploadException;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;
 
import cn.itcast.utils.FileUtils;
 
/**
  * 文件上传的Servlet
  */
@SuppressWarnings ( "all" )
public class FileUploadServlet extends HttpServlet {
 
protected void doGet( final HttpServletRequest request, HttpServletResponse response) {
 
try {
//1.创建磁盘文件工厂对象
DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
//2.创建核心的解析类对象
ServletFileUpload fileUpload = new ServletFileUpload(diskFileItemFactory);
//3.设置监听文件上传进度的监听器,以便获得文件上传的进度
fileUpload.setProgressListener( new ProgressListener() {
 
@Override
public void update( long pBytesRead, long pContentLength, int pItems) {
double pRead = pBytesRead;
double pLength = pContentLength;
//获得数字格式化对象--百分比
NumberFormat format = NumberFormat.getPercentInstance();
//保留2位小数点
format.setMaximumFractionDigits( 2 );
//计算文件上传的进度
String percent = format.format(pRead/pLength);
System.out.println( "已经上传的进度:" +percent);
//将文件上传的进度保存在Session域中
request.getSession().setAttribute( "progress" , percent);
 
}
});
 
//解决中文文件名上传的乱码的问题
fileUpload.setHeaderEncoding( "UTF-8" );
 
//4.解析请求,获得表单项的集合对象
List<FileItem> list = fileUpload.parseRequest(request);
//5.遍历表单项的集合
for (FileItem fileItem : list) {
//6.判断当前的表单项是否是文件项
if (fileItem.isFormField()){
//6.1.如果是普通文本项,获得参数的名称和值
String name = fileItem.getFieldName();
String value = fileItem.getString( "UTF-8" );
System.out.println(name+ ":" +value);
} else {
//6.2.如果是文件项,获取文件内容,使用流写入到服务器磁盘中
String fileName = fileItem.getName();
//文本保存的根目录
String baseDir = "C:\\Users\\fudingcheng\\Desktop\\file" ;
//获得文件保存子目录
String childDir = FileUtils.getDirNameByDate();
//判断子目录是否存在
File realDir = new File(baseDir+childDir);
if (!realDir.exists()){
realDir.mkdirs();
}
//将文件写到磁盘中
fileItem.write( new File(baseDir+childDir, fileName));
}
}
} catch (Exception e) {
e.printStackTrace();
}
 
}
 
 
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}

ShowFileUploadProgress.java
[Java]  纯文本查看  复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
/**
  * 获取文件上传进度的Servlet
  */
@SuppressWarnings ( "serial" )
public class ShowFileUploadProgress extends HttpServlet {
 
 
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String percent = (String) request.getSession().getAttribute( "progress" );
response.getWriter().print(percent);
}
 
 
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
 
}

FileUtils.java
[Java]  纯文本查看  复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
import java.util.Calendar;
 
/**
* 文件上传的工具类
*/
public class FileUtils {
 
/**
* 生成子目录的方法
*/
public static String getDirNameByDate(){
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH)+ 1 ;
int day = calendar.get(Calendar.DAY_OF_MONTH);
return "/" +year+ "/" +month+ "/" +day;
}
 
}


效果图展示

;