- 本文参考了网络上大牛写的文档稍加改造,如侵权请联系
总体结构
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/b8ddbfe9160559a6306c2d9797e814f2.png)
配置文件
#webUploader参数配置
spring:
thymeleaf:
prefix: classpath:/paga/
suffix: .html
http:
multipart:
max-file-size: 100000Mb
max-request-size: 100000Mb
server:
port: 80
async : false
#文件保存路径
filepath: 'E:/test/'
前端页面
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<meta charset="UTF-8" />
<title>文件上传</title>
<link type="text/css" th:href="@{bootstrap.min.css}" rel="stylesheet" />
<link type="text/css" th:href="@{webuploader.css}" rel="stylesheet" />
<!--<link rel="stylesheet" href="../static/bootstrap.min.css"/>-->
<!--<link rel="stylesheet" href="../static/webuploader.css"/>-->
</head>
<body >
<div id="uploader" class="wu-example" >
<!--用来存放文件信息-->
<div id="thelist" class="uploader-list" style="width:500px;"></div>
<div class="btns">
<div id="picker">选择文件</div>
</div>
<!--<div id="StopBtn" class="webuploader-pick"-->
<!--style="float: left; margin-right: 10px" status="suspend" >暂停上传-->
<!--</div>-->
</div>
<script th:src="@{jquery-3.1.1.min.js}"></script>
<script th:src="@{md5.js}"></script>
<script th:src="@{webuploader.min.js}"></script>
<!--<script src="../static/jquery-3.1.1.min.js"></script>-->
<!--<script src="../static/md5.js"></script>-->
<!--<script src="../static/webuploader.min.js"></script>-->
<script type="text/javascript">
//页面初始化
// $(function(){
// $("#StopBtn").hide(); //隐藏暂停按钮
// });
var md5File;
//监听分块上传过程中的时间点
var register = WebUploader.Uploader.register({
"before-send-file":"beforeSendFile", // 整个文件上传前
"before-send":"beforeSend", // 每个分片上传前
"after-send-file": "afterSendFile" // 分片上传完毕
},{
//时间点1:所有分块进行上传之前调用此函数 ,检查文件存不存在
beforeSendFile:function(file){
var deferred = WebUploader.Deferred();
file.md5File = hex_md5(file.name+file.size);
$.ajax({
type:"POST",
url:"/checkFile",
data:{
md5File: file.md5File, //文件唯一标记
name:file.name //文件名,在后台拼接完整的文件路径
},
async: true, // 同步
dataType:"json",
success:function(response){
if(response){ //文件存在,跳过,提示文件存在
$('#' + file.id).find('p.state').text("该文件已存在");
// WebUploader.Uploader.destroy(file);
deferred.reject(file);
}else{
deferred.resolve(); //文件不存在或不完整,发送该文件
}
}
} , function (jqXHR, textStatus, errorThrown) { //任何形式的验证失败,都触发重新上传
deferred.resolve();
} );
return deferred.promise();
},
//时间点2:如果有分块上传,则每个分块上传之前调用此函数,判断分块存不存在
beforeSend:function(block){
var deferred = WebUploader.Deferred();
$.ajax({
type:"POST",
url:"/checkChunk",
data:{
md5File: block.file.md5File, //文件唯一标记
chunk:block.chunk, //当前分块下标
},
dataType:"json",
success:function(response){
if(response){
deferred.reject(); //分片存在,跳过
}else{
deferred.resolve(); //分块不存在或不完整,重新发送该分块内容
}
}
}, function (jqXHR, textStatus, errorThrown) { //任何形式的验证失败,都触发重新上传
deferred.resolve();
});
return deferred.promise();
},
//时间点3:分片上传完成后,通知后台合成分片
afterSendFile: function (file) {
console.log("=====",file)
var chunksTotal = Math.ceil(file.size / (5*1024*1024));
if (chunksTotal >= 1) {
//合并请求
var deferred = WebUploader.Deferred();
$.ajax({
type: "POST",
url: "/merge",
data: {
name: file.name,
md5File: file.md5File,
chunks: chunksTotal
},
cache: false,
async: false, // 同步
dataType: "json",
success:function(response){
if(response){
$('#' + file.id).find('p.state').text('上传成功');
$('#' + file.id).find('.progress').fadeOut();
$("#picker").show();//显示上传按钮
//$("#StopBtn").hide();//隐藏暂停按钮
}else{
$('#' + file.id).find('p.state').text('上传失败');
//进度条变红
$('#' + file.id).find(".progress").find(".progress-bar").attr("class", "progress-bar progress-bar-danger");
deferred.reject();
}
}
})
return deferred.promise();
}
}
});
var uploader = WebUploader.create({
auto: true,// 选完文件后,是否自动上传。
swf: '../static/Uploader.swf',// swf文件路径
server: '/upload',// 文件接收服务端。
pick: '#picker',// 选择文件的按钮。可选。
chunked:true,//开启分片上传
chunkSize:5*1024*1024,//5M
chunkRetry: 3,//错误重试次数
threads: 100, //上传并发数
// fileSizeLimit: 2000 * 1024 * 1024,//最大10GB
// fileSingleSizeLimit: 2000 * 1024 * 1024,
//fileNumLimit: 100 // 最大上传并发数
});
// $("#StopBtn").click(function () {
// console.log($('#StopBtn').attr("status"));
// var status = $('#StopBtn').attr("status");
// if (status == "suspend") {
// console.log("当前按钮是暂停,即将变为继续");
// $("#StopBtn").html("继续上传");
// $("#StopBtn").attr("status", "continuous");
// console.log("当前所有文件==="+uploader.getFiles());
// console.log("=============暂停上传==============");
// uploader.stop(true);
// console.log("=============所有当前暂停的文件=============");
// console.log(uploader.getFiles("interrupt"));
// } else {
// console.log("当前按钮是继续,即将变为暂停");
// $("#StopBtn").html("暂停上传");
// $("#StopBtn").attr("status", "suspend");
// console.log("===============所有当前暂停的文件==============");
// console.log(uploader.getFiles("interrupt"));
// uploader.upload(uploader.getFiles("interrupt"));
// }
// });
//上传添加参数
uploader.on('uploadBeforeSend', function (block, data, headers) {
data.md5File=block.file.md5File;
});
// 当有文件被添加进队列的时候
uploader.on( 'fileQueued', function( file ) {
//$("#picker").hide();//隐藏上传按钮
//$("#StopBtn").show();//显示暂停按钮
$("#thelist").append( '<div id="' + file.id + '" class="item">' +
'<h4 class="info">' + file.name + '</h4>' +
'<p class="state"></p>' +
'</div>' );
});
// 文件上传过程中创建进度条实时显示。
uploader.on( 'uploadProgress', function( file, percentage ) {
var $li = $( '#'+file.id ),
$percent = $li.find('.progress .progress-bar');
// 避免重复创建
if ( !$percent.length ) {
$percent = $('<div class="progress progress-striped active">' +
'<div class="progress-bar" role="progressbar" style="width: 0%"></div>' +
'</div>').appendTo( $li ).find('.progress-bar');
}
$li.find('p.state').text('上传中。。。');
$percent.css( 'width', percentage * 100 + '%' );
});
</script>
</body>
</html>
Controller
package com.uda.controller;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
/**
* 文件上传controller
*/
@Controller
public class Uploader {
//注入文件保存的路径
@Value("${filepath}")
private String filepath;
@GetMapping( "/")
public String page(){
return "upload";
}
/**
* 检查文件存在与否
*/
@PostMapping("checkFile")
@ResponseBody
public Boolean checkFile(
//@RequestParam(value = "md5File") String md5File,
@RequestParam(value = "name") String name) {
//合并后的文件
File file = new File(filepath + name);
//判断该文件是否目录(目录表示文件已经分片并合并成功/已经上传)
boolean exists = file.exists();
System.out.println("======" + file.getPath());
System.out.println(exists);
return exists;
}
/**
* 检查分片存不存在
*/
@PostMapping("checkChunk")
@ResponseBody
public Boolean checkChunk(@RequestParam(value = "md5File") String md5File,
@RequestParam(value = "chunk") Integer chunk) {
Boolean exist = false;
String path = filepath + md5File + "/"; //分片存放目录
String chunkName = chunk+ ".tmp"; //分片文件名
File file = new File(path+chunkName);
if (file.isDirectory()) {
exist = true;
}
return exist;
}
/**
* 修改上传
*/
@PostMapping("upload")
@ResponseBody
public Boolean upload(@RequestParam(value = "file") MultipartFile file,
@RequestParam(value = "md5File") String md5File,
@RequestParam(value = "chunk",required= false) Integer chunk) { //第几片,从0开始
String path = filepath+md5File+"/";
File dirfile = new File(path);
if (!dirfile.exists()) { //目录不存在,创建目录
dirfile.mkdirs();
}
String chunkName;
if(chunk == null) { //表示是小文件,还没有一片
chunkName = "0.tmp";
}else {
chunkName = chunk+ ".tmp";
}
String filePath = path+chunkName;
File savefile = new File(filePath);
try {
if (!savefile.exists()) {
savefile.createNewFile(); //文件不存在,则创建
}
file.transferTo(savefile); //将文件保存
} catch (IOException e) {
return false;
}
return true;
}
/**
* 合成分片
*/
@PostMapping("merge")
@ResponseBody
public Boolean merge(@RequestParam(value = "chunks",required =false) Integer chunks,
@RequestParam(value = "md5File") String md5File,
@RequestParam(value = "name") String name) throws Exception {
long start = System.currentTimeMillis();
FileOutputStream fileOutputStream = new FileOutputStream(filepath+name); //合成后的文件
try {
byte[] buf = new byte[1024];
for(long i=0;i<chunks;i++) {
String chunkFile=i+".tmp";
File file = new File(filepath+md5File+"/"+chunkFile);
InputStream inputStream = new FileInputStream(file);
int len = 0;
while((len=inputStream.read(buf))!=-1){
fileOutputStream.write(buf,0,len);
}
inputStream.close();
}
//删除md5目录及临时文件
File file = new File(filepath+md5File);
File[] files = file.listFiles();
for (File f : files) {
f.delete();
}
file.delete();
} catch (Exception e) {
System.out.println(System.currentTimeMillis() - start);
return false;
}finally {
fileOutputStream.close();
}
System.out.println(System.currentTimeMillis() - start);
return true;
}
}