java这块就没啥好说的了。进度条样式来自 bootstrap ,文件用 jquery 的 ajax 来提交 post 请求(上传),然后进度条事件来实现进度条(改变进度条样式),通过各种计算就可以进一步计算出速度和剩余时间。

最终实现效果图:

前端代码:

1
2
3
4
5
6
7
8
9
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<title>文件上传测试页</title>

<!-- Bootstrap -->
<link href="./css/bootstrap.css" rel="stylesheet">

<!-- HTML5 shim 和 Respond.js 是为了让 IE8 支持 HTML5 元素和媒体查询(media queries)功能 -->
<!-- 警告:通过 file:// 协议(就是直接将 html 页面拖拽到浏览器中)访问页面时 Respond.js 不起作用 -->
<!--[if lt IE 9]>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/html5shiv.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dest/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="container thumbnail" style="padding: 100px 100px;">
<div class="row">
<h1>文件上传测试页</h1>
</div>
<div class="row">
<form id="fileuploadform" action="${pageContext.request.contextPath}/fileupload.do" method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="exampleInputFile">File input</label>
<input type="file" id="exampleInputFile" name="exampleInputFile">
<p class="help-block" id="msg">请点击提交按钮提交文件</p>
</div>
<input id="uploadbutton" type="button" class="btn btn-default" value="提交" onclick="upload()"/>
</form>
</div>

<!-- 进度条 -->
<div class="progress row">
<div id="progressbar" class="progress-bar progress-bar-striped" role="progressbar" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100" style="width: 0%"></div>
</div>

<!-- 上传速度 -->
<div id="showUploadInfo" class="row">
上传速度:<label id="uploadspeed"></label><br />
剩余时间:<label id="timeleft"></label><br />
</div>

<!-- 显示文件信息 -->
<div id="showFileInfo" class="row">
文件名称:<label id="upfileName"></label><br />
文件大小:<label id="upfileSize"></label><br />
文件类型:<label id="upfileType"></label><br />
</div>
</div>


<script type="application/javascript">
// 上传文件
function upload(){
var checkFile = $("#exampleInputFile").val();
if(null==checkFile || ""==checkFile){
$("#msg").text("文件为空,请选择文件!");
}else{
var formData = new FormData($("#fileuploadform")[0]);
$.ajax({
type: "POST",
enctype:'multipart/form-data',
url: '${pageContext.request.contextPath}/fileupload.do',
data: formData,
cache:false,
processData:false,
contentType:false,
error:function(result){
console.log("ajax error: "+result);
flag = false;
$("#msg").text("Ajax upload failed: "+ result);
},
success: function(result){
$("#msg").text("ajax upload succeed:"+result);
},
xhr: function () {
var xhr = $.ajaxSettings.xhr();
if (xhr.upload) {
//处理进度条的事件
xhr.upload.addEventListener("progress", progressHandle, false);
//加载完成的事件
xhr.addEventListener("load", completeHandle, false);
//加载出错的事件
xhr.addEventListener("error", failedHandle, false);
//加载取消的事件
xhr.addEventListener("abort", canceledHandle, false);
//初始化
initProgress();
return xhr;
}
}
}, 'json');
}
}

//初始化
function initProgress() {
//上传中的进度条样式
$('#progressbar').addClass("active");
$('#progressbar').addClass("progress-bar-info");
$('#progressbar').removeClass("progress-bar-success");

//禁用上传按钮
$('#uploadbutton').attr('disabled',true);

//显示文件信息
$('#upfileName').text($('#exampleInputFile')[0].files[0].name);
$('#upfileSize').text(($('#exampleInputFile')[0].files[0].size/1024/1024).toFixed(1)+"MB");
$('#upfileType').text($('#exampleInputFile')[0].files[0].type);
}

//重置进度条的函数
function resetProgress() {
$("#exampleInputFile").val('');
$('#uploadbutton').attr('disabled',false);
//$("#msg").text("请点击提交按钮提交文件。");
}
//进度条更新
var nowTime, timeDiff, loadedDiff, speed, preTime, count = 0, preLoad, preTime;

function progressHandle(e) {
nowTime = (new Date()).getTime(); //现在的时间

timeDiff = (nowTime - preTime) / 1000; //距离上次的时间
loadedDiff = e.loaded - preLoad; //距离上次的载入字节数

speed = parseInt(loadedDiff / timeDiff); //速度
timeleft = Math.round((e.total - e.loaded) / speed); //剩余时间



console.log("已上传:"+ e.loaded +" 总计:"+ e.total);

//完成百分比 设置进度条
var percent = e.loaded / e.total * 100;
$('#progressbar').css("width", percent+"%");
$('#progressbar').text(Math.round(percent)+"%");

//设置上传速度 剩余时间
if (count > 10) {
if (speed>1024) {
$('#uploadspeed').text(Math.round(speed / 1000 / 1024) + "m/s");
} else {
$('#uploadspeed').text(speed + "k/s");
}
$('#timeleft').text( parseInt(timeleft / 60) + "分 " + timeleft % 60 + "秒");
count = 0;
}
count++;

preTime = nowTime;
preLoad = e.loaded;

if (percent == 100) {
$("#msg").text("上传完成, 请稍后..");
$('#progressbar').removeClass("active");
$('#progressbar').removeClass("progress-bar-info");
$('#progressbar').addClass("progress-bar-success");
} else {
$("#msg").text("上传中...");
}
};
//上传完成处理函数
function completeHandle(e) {
$("#msg").text("上传成功!");
setTimeout(resetProgress, 2000);
};
//上传出错处理函数
function failedHandle(e) {
$("#msg").text("Upload failed.");
};
//上传取消处理函数
function canceledHandle(e) {
$("#msg").text("Upload canceled.");
};
</script>

<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script src="./js/jquery-3.3.1.min.js"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="./js/bootstrap.js"></script>
</body>
</html>

java 的 controller 类:

1
2
3
4
5
6
7
8
9
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
package com.crazykid.springboot.web.springbootssm.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;

@Controller
public class FileUpload {
@RequestMapping(value = "/fileupload.do", method = RequestMethod.POST)
@ResponseBody
public String FileUpload(HttpServletRequest request, @RequestParam("exampleInputFile")MultipartFile file) {
if(file.isEmpty()){
return "false";
}

//获取文件名称和大小
String fileName = file.getOriginalFilename();
int size = (int) file.getSize();
System.out.println(fileName + "-->" + size);

//获取项目的目录,设置保存地址
String destPath = request.getSession().getServletContext().getRealPath("temp/fileupload/");
File dest = new File(destPath + fileName);
if(!dest.getParentFile().exists()){ //判断文件父目录是否存在
dest.getParentFile().mkdir(); //不存在的话创建文件夹
}
try {
file.transferTo(dest); //保存文件
return "true";
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return "false";
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return "false";
}
}
}