1、下载组件
1)、直接下载
# 下载地址
http://fex.baidu.com/webuploader/download.html
# github下载地址
https://github.com/fex-team/webuploader/releases
2)、自己编译打包
git命令行工具
node & npm命令行工具
grunt (npm install grunt-cli -g)
# 1、克隆代码
git clone https://github.com/fex-team/webuploader.git
# 2、安装node依赖
npm install
# 3、执行grunt dist,此动作会在dist目录下面创建合并版本的js, 包括通过uglify压缩的min版本。
grunt dist
2、前端页面index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件上传</title>
<!--引入CSS-->
<link rel="stylesheet" type="text/css" href="webuploader-0.1.5/webuploader.css">
<!--引入JS-->
<script type="text/javascript" src="jquery/jquery-3.6.1.min.js"></script>
<script type="text/javascript" src="webuploader-0.1.5/webuploader.js"></script>
</head>
<body>
<div id="uploader" class="wu-example">
<!--用来存放文件信息-->
<div id="thelist" class="uploader-list"></div>
<div class="btns">
<div id="picker">选择文件</div>
<button id="ctlBtn" class="btn btn-default">开始上传</button>
</div>
</div>
<script type="text/javascript">
$(function() {
//开始上传按钮
var $btn = $('#ctlBtn');
//文件信息显示区域
var $list = $('#thelist');
//当前状态
var state = 'pending';
//初始化Web Uploader
var uploader = WebUploader.create({
// swf文件路径
swf: '/webuploader-0.1.5/Uploader.swf',
// 文件接收服务端。
//server: 'http://www.hangge.com/upload.php',
server:'/fileupload',
// 选择文件的按钮。可选。
// 内部根据当前运行是创建,可能是input元素,也可能是flash.
pick: '#picker',
//设置文佳上传的类型格式
// accept: { //不建议使用,使用时选择文件div失效
// title: 'file',
// extensions: 'xls,xlsx,word,doc,ppt,docx,rtf,ppt,txt,pptx,pdf',
// mimeTypes: '.xls,.xlsx,.word,.doc,.ppt,.docx,.rtf,.ppt,.txt,.pptx,.pdf'
// },
// 设置分片
chunked: true,
// 设置分片大小为5M
chunkSize: 5242880
});
// 当有文件被添加进队列的时候(选择文件后调用)
uploader.on( 'fileQueued', function( file ) {
$list.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 );
$li.find('p.state').text('上传中(' + parseInt(percentage * 100) + '%)');
});
// 文件上传成功后会调用
uploader.on( 'uploadSuccess', function( file ) {
$( '#'+file.id ).find('p.state').text('已上传');
savefilemanager(file);
});
// 文件上传失败后会调用
uploader.on( 'uploadError', function( file ) {
$( '#'+file.id ).find('p.state').text('上传出错');
});
// 文件上传完毕后会调用(不管成功还是失败)
uploader.on( 'uploadComplete', function( file ) {
$( '#'+file.id ).find('.progress').fadeOut();
});
// all事件(所有的事件触发都会响应到)
uploader.on( 'all', function( type ) {
if ( type === 'startUpload' ) {
state = 'uploading';
} else if ( type === 'stopUpload' ) {
state = 'paused';
} else if ( type === 'uploadFinished' ) {
state = 'done';
}
if ( state === 'uploading' ) {
$btn.text('暂停上传');
} else {
$btn.text('开始上传');
}
});
function savefilemanager(file) {
console.log('filename='+file.name)
let param = {};
param.id = file.id;
param.name = file.name;
param.size = file.size;
param.type = file.type;
param.ext = file.ext;
param.lastModifiedDate = file.lastModifiedDate;
param.md5 = file.md5;
$.ajax({
url: "/uploadFileEnd",
data: JSON.stringify(param),
method: "post",
dataType: "json",
contentType: 'application/json',
success: function (data) {
console.log(data)
if (data.success) {
$.messager.alert("系统提示","添加成功","info");
} else {
$.messager.alert("系统提示","添加失败","error");
}
}
});
};
// 开始上传按钮点击事件响应
$btn.on( 'click', function() {
if ( state === 'uploading' ) {
uploader.stop();
} else {
uploader.upload();
}
});
});
</script>
</body>
</html>
3、后端代码
package com.shenma2005.vo;
import lombok.Data;
import java.io.Serializable;
/**
* @author 军哥
* @version 1.0
* @description: FileUploadEndVo
* @date 2022/12/9 10:02
*/
@Data
public class FileUploadEndVo implements Serializable {
private String id;
private String name;
private Integer size;
private String type;
private String ext;
private String md5;
private String lastModifiedDate;
}
package com.shenma2005.controller;
import com.shenma2005.vo.FileUploadEndVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.UUID;
/**
* @author 军哥
* @version 1.0
* @description: Web Uploader 分片上传接口
* @date 2022/12/9 8:19
*/
@Controller
@Slf4j
@RequestMapping(value = "/")
public class IndexController {
@Autowired
private RedisTemplate redisTemplate;
final String uploadDir = "D:\\temp\\upload";
@GetMapping(value = "/index")
public String index() {
return "index";
}
/**
* 接收上传的分片文件
* @param request
* @param response
* @return
* @throws Exception
*/
@RequestMapping("/fileupload")
@ResponseBody
public String doulefileupload(HttpServletRequest request, HttpServletResponse response) throws Exception {
String id = request.getParameter("id");
String name = request.getParameter("name");
String type = request.getParameter("type");
String lastModifiedDate = request.getParameter("lastModifiedDate");
String size = request.getParameter("size");
String chunks = request.getParameter("chunks");
String chunk = request.getParameter("chunk");
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
MultipartFile file = multipartRequest.getFile("file");
long size1 = file.getSize();
String originalFilename = file.getOriginalFilename();
System.out.println(""+size1+originalFilename);
// 更新上传文件信息
String uploadFileKey = "UPLOAD_" + id + "_" + size;
log.info("uploadFileKey1="+uploadFileKey);
redisTemplate.opsForHash().put(uploadFileKey, "id", id);
redisTemplate.opsForHash().put(uploadFileKey, "name", name);
redisTemplate.opsForHash().put(uploadFileKey, "type", type);
redisTemplate.opsForHash().put(uploadFileKey, "lastModifiedDate", lastModifiedDate);
redisTemplate.opsForHash().put(uploadFileKey, "size", size);
redisTemplate.opsForHash().put(uploadFileKey, "chunks", chunks);
redisTemplate.opsForHash().put(uploadFileKey, "chunk", chunk);
// 准备目录
String storeDir = uploadDir + File.separator + uploadFileKey;
log.info("storeDir1="+storeDir);
File fileFolder = new File(storeDir);
if (!fileFolder.exists()) {
boolean mkdirs = fileFolder.mkdirs();
log.info("准备工作,创建文件夹,fileFolderPath:{},mkdirs:{}", storeDir, mkdirs);
}
// 存储文件
String tempName = UUID.randomUUID().toString();
String fileName = storeDir + File.separator + tempName;
log.info("fileName1="+fileName);
File dest = new File(fileName);
file.transferTo(dest);
// 上传成功,设置成功标识
String storeFileKey = "STORE_" + id + "_" + size;
log.info("storeFileKey1={},chunk={}", storeFileKey,chunk);
redisTemplate.opsForHash().put(storeFileKey, chunk, fileName);
return name;
}
/**
* 所有分片上传成功,开始问卷合并
* @param fileUploadEndVo
* @return
*/
@PostMapping(value = "/uploadFileEnd")
@ResponseBody
public String uploadFileEnd(@RequestBody FileUploadEndVo fileUploadEndVo) {
System.out.println(""+fileUploadEndVo.toString());
try {
// 检查文件是否全部上传完成
String uploadFileKey = "UPLOAD_" + fileUploadEndVo.getId() + "_" + fileUploadEndVo.getSize();
log.info("uploadFileKey="+uploadFileKey);
String chunks = (String)redisTemplate.opsForHash().get(uploadFileKey, "chunks");
log.info("chunks2="+chunks);
Boolean isFinish = true;
String storeFileKey = "STORE_" + fileUploadEndVo.getId() + "_" + fileUploadEndVo.getSize();
for (int index = 0; index < Integer.valueOf(chunks); index++) {
log.info("storeFileKey2="+storeFileKey);
if(!redisTemplate.opsForHash().hasKey(storeFileKey, ""+index)) {
isFinish = false;
log.error("storeFileKey={},key={}", storeFileKey, ""+index);
break;
}
}
if(!isFinish) {
return "ERROR";
}
// 合并文件
String storeFile = uploadDir + File.separator + UUID.randomUUID().toString() + "." + fileUploadEndVo.getExt();
File resultFile = new File(storeFile);
BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(resultFile));
int bufSize = 1024*4;
byte[] buffer = new byte[bufSize];
for (int index = 0; index < Integer.valueOf(chunks); index++) {
String tempFile = (String)redisTemplate.opsForHash().get(storeFileKey, ""+index);
BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(tempFile));
int readcount;
while ((readcount = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, readcount);
}
inputStream.close();
Files.delete(Paths.get(tempFile));
}
outputStream.close();
// 删除临时文件:直接删除目录
String storeDir = uploadDir + File.separator + uploadFileKey;
Files.deleteIfExists(Paths.get(storeDir));
// 存入数据库,并删除缓存文件
redisTemplate.delete(uploadFileKey);
redisTemplate.delete(storeFileKey);
} catch (IOException e) {
e.printStackTrace();
} finally {
}
return fileUploadEndVo.getName();
}
}
4、修改配置文件
## 文件上传大小限制
spring.servlet.multipart.max-request-size=100MB
spring.servlet.multipart.max-file-size=100MB
参考文章