黑马程序员技术交流社区

标题: 【西安校区】基于FileUpload组件实现文件上传进度条的显示 [打印本页]

作者: 西安Java组    时间: 2017-12-15 20:10
标题: 【西安校区】基于FileUpload组件实现文件上传进度条的显示
本帖最后由 西安Java组 于 2017-12-15 20:20 编辑

· 技术背景
   文件上传是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] 纯文本查看 复制代码

<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">
文件描述:<input type="text" name="desc"><br/>
文件:<input type="file" name="file"><br/>
<input type="submit" value="提交">
</form>
</body>


Javascript代码
[JavaScript] 纯文本查看 复制代码

<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] 纯文本查看 复制代码
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] 纯文本查看 复制代码
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] 纯文本查看 复制代码

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;
}

}


效果图展示






欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2