由于我的项目的前端用的是Layui框架,所以这里可以直接使用Layui框架的上传组件Upload,参考官方文档:上传组件 upload - Layui 文档
实现效果:
这样事情就简单起来了,下面是具体实现代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>上传Excel</title>
<!-- 请勿在项目正式环境中引用该 layui.css 地址 -->
</head>
<body>
<div class="layui-fluid" id="GetExcel">
<div class="layui-col-md12">
<div class="layui-upload">
<div class="layui-upload-list">
<table class="layui-table">
<colgroup>
<col style="min-width: 100px;">
<col width="150">
<col width="260">
<col width="150">
</colgroup>
<thead>
<th>文件名</th>
<th>大小</th>
<th>上传进度</th>
<th>操作</th>
</thead>
<tbody id="ID-upload-demo-files-list"></tbody>
</table>
</div>
<button type="button" class="layui-btn layui-btn-normal" id="ID-upload-demo-files">选择文件</button>
<button type="button" class="layui-btn" id="ID-upload-demo-files-action">开始上传</button>
</div>
</div>
</div>
<!-- 请勿在项目正式环境中引用该 layui.js 地址 -->
<script>
layui.define(function () {
var upload = layui.upload;
var element = layui.element;
var $ = layui.$;
// 制作多文件上传表格
let uploadListIns = upload.render({
elem: '#ID-upload-demo-files',
// 列表元素对象
elemList: $('#ID-upload-demo-files-list'),
url: '/tri/GetExcel',
accept: 'file',
multiple: true,
number: 3,
auto: false,
bindAction: '#ID-upload-demo-files-action',
choose: function(obj){
let that = this;
// 将每次选择的文件追加到文件队列
let files = this.files = obj.pushFile();
// 读取本地文件
obj.preview(function(index, file, result){
that.data = {
'file': file
}
let tr = $(['<tr id="upload-'+ index +'">',
'<td>'+ file.name +'</td>',
'<td>'+ (file.size/1024).toFixed(1) +'kb</td>',
'<td><div class="layui-progress" lay-filter="progress-demo-'+ index +'"><div class="layui-progress-bar" lay-percent=""></div></div></td>',
'<td>',
'<button class="layui-btn layui-btn-xs demo-reload layui-hide">重传</button>',
'<button class="layui-btn layui-btn-xs layui-btn-danger demo-delete">删除</button>',
'</td>',
'</tr>'].join(''));
// 单个重传
tr.find('.demo-reload').on('click', function(){
obj.upload(index, file);
});
// 删除
tr.find('.demo-delete').on('click', function(){
// 删除对应的文件
delete files[index];
// 删除表格行
tr.remove();
// 清空 input file 值,以免删除后出现同名文件不可选
uploadListIns.config.elem.next()[0].value = '';
});
that.elemList.append(tr);
// 渲染新加的进度条组件
element.render('progress');
});
},
// 成功的回调
done: function(res, index, upload){
let that = this;
// 上传成功
if(res.code === 500){
let tr = that.elemList.find('tr#upload-'+ index),
tds = tr.children();
// 清空操作
tds.eq(3).html('');
// 删除文件队列已经上传成功的文件
delete this.files[index];
return;
}
this.error(index, upload);
},
// 多文件上传完毕后的状态回调
allDone: function(obj){
layer.msg('上传文件成功', {
icon: 1,
time: 1000 //1秒关闭(如果不配置,默认是3秒)
});
},
// 错误回调
error: function(index, upload){
let that = this;
let tr = that.elemList.find('tr#upload-'+ index);
let tds = tr.children();
// 显示重传
tds.eq(3).find('.demo-reload').removeClass('layui-hide');
},
progress: function(n, elem, e, index){
// 执行进度条。n 即为返回的进度百分比
element.progress('progress-demo-'+ index, n + '%');
}
});
});
</script>
</body>
</html>
虽然事情变得简单起来了,但也有一些注意事项,不然还是会出现烦人的错误。
1、注意引用库时layui.css和layui.js的顺序,layui.js一定要在layui.css的下面
<!-- 框架样式 -->
<link rel="stylesheet" media="all" href="layui-v2.7.6/css/layui.css?v=2.7.6">
<!--一定要放在这里,放在layui.css的下面,不然上传excel组件会找不到file,也就是出现"Required request part 'file' is not present"错误-->
<script src="layui-v2.7.6/layui.js?v=2.7.6"></script>
2、注意不能用headers来手动设置Content-Type,在Layui框架中会自动设置Content-Type
//headers:{'Content-Type': 'multipart/form-data; boundary=YOUR_BOUNDARY'},
//不能手动设置Content-Type,不然会有"Required request part 'file' is not present"错误