一、官方文档参考地址
http://fex-team.github.io/webuploader/document.html
二、功能需求
点击一个按钮,直接打开文件选择窗口,选中多个文件后,点击窗口【确定】按钮后,直接开始上传。
三、实现
由于文件普遍为较大文件,所以使用分片上传的方式来实现。使用的js框架为百度的webuploader。
1.前端部分:
首先页面引入webuploader.js插件
<script type="text/javascript" charset="UTF-8" th:src="@{/scripts/common/file/upload/webuploader.js}"></script>
上传按钮部分:
<a class="btn btn-default btn-sm" id="upload_btn" > 上传 </a>
<div style="display:none;">
<span id="picker" class="showclass">点击上传文件</span>
</div>
id=“picker” 这部分要注意,后面会用到,webuploader是会对一个指定id的元素,在下方生成一些html代码,来辅助上传。
新建个uploader.js引入到页面,本js主要就是对webuploader的一些初始化之类的。
var SbzUploader = function(conf) {
}
var sbzUploadConf =
{
autoUpload : false, sbzFile : 'sbzUploadFile', docType : 'PDM', businessId : '1111111112312312321', fileId : '',
complete : function() {
alert('success');
}, progress : function(file, percentage) {
console.log()
}
}
var $sbzFile = $('#' + sbzUploadConf.sbzFile);
/**
* 上传的AJAX
*/
var sbzUploadAjax =
function(uri, data, success, fail) {
$.ajax({
url : uri, data : JSON.stringify(data), type : "POST", contentType : "application/json;charset=UTF-8",
dataType : "json"
}).done(function(res) {
if (res.buinessException && res.code < 9) {
sbz.Msg.showMsg(res.code, res.message)
if (fail) {
fail(res);
}
} else if (success) {
success(res);
}
}).fail(function(res) {
if (fail) {
fail(res);
} else {
sbz.Msg.error(res.message + res.responseText);
}
});
}
/**
*
*/
var _sbzUploadConf =
{
chunkSize : 5 * 1024 * 1024, fileNumLimit : 1024, fileSizeLimit : 1024 * 1024 * 1024 * 10,
fileSingleSizeLimit : 1024 * 1024 * 1024
}
// HOOK 这个必须要再uploader实例化前面
WebUploader.Uploader.register({
'before-send-file' : 'beforeSendFile', 'before-send' : 'beforeSend'
}, {
beforeSendFile : function(file) {
console.log("beforeSendFile");
// Deferred对象在钩子回掉函数中经常要用到,用来处理需要等待的异步操作。
var task = new $.Deferred();
// 根据文件内容来查询MD5
uploader.md5File(file).progress(function(percentage) { // 及时显示进度
console.log('md5 per:', percentage);
getProgressBar(file, percentage, "MD5", "分片计算");
}).then(function(val) { // 完成
console.log('md5 result:', val);
file.md5 = val;
file.uid = WebUploader.Base.guid();
file.bid = sbzUploadConf.businessId;
// 进行md5判断
$.post("/document/uploader/checkFileMd5", {
uid : file.uid, md5 : file.md5, bid : sbzUploadConf.businessId
}, function(data) {
console.log(data.status);
var status = data.status;
task.resolve();
if (status == 101) {
// 文件不存在,那就正常流程
// hky add bid
sbzUploadConf.businessId = '11111111'
} else if (status == 100) {
// 忽略上传过程,直接标识上传成功;
//uploader.skipFile(file);
//file.pass = true;
} else if (status == 102) {
// 部分已经上传到服务器了,但是差几个模块。
file.missChunks = data.data;
}
});
});
return $.when(task);
}, beforeSend : function(block) {
console.log("block")
var task = new $.Deferred();
var file = block.file;
var missChunks = file.missChunks;
var blockChunk = block.chunk;
console.log("当前分块:" + blockChunk);
console.log("missChunks:" + missChunks);
if (missChunks !== null && missChunks !== undefined && missChunks !== '') {
var flag = true;
for (var i = 0; i < missChunks.length; i++) {
if (blockChunk == missChunks[i]) {
console.log(file.name + ":" + blockChunk + ":还没上传,现在上传去吧。");
flag = false;
break;
}
}
if (flag) {
task.reject();
} else {
task.resolve();
}
} else {
task.resolve();
}
return $.when(task);
}
});
// 实例化
var uploader =
WebUploader.create({
pick : {
id : '#picker'
},
name : 'sbz-uploader-file',
formData : {
uid : 0,
md5 : '',
bid : '', chunkSize : _sbzUploadConf.chunkSize
},
chunked : true,
chunkSize : _sbzUploadConf.chunkSize, // 字节 1M分块
threads : 3,
server : '/document/uploader/fileUpload',
auto : true,
// 禁掉全局的拖拽功能。这样不会出现图片拖进页面的时候,把图片打开。
disableGlobalDnd : false,
fileNumLimit : _sbzUploadConf.fileNumLimit,
fileSizeLimit : _sbzUploadConf.fileSizeLimit,
fileSingleSizeLimit : _sbzUploadConf.fileSingleSizeLimit
});
// 当有文件被添加进队列的时候
uploader.on('fileQueued', function(file) {
console.log("fileQueued");
uploadFlag = true; // hky add
var uploadFileProgressHtml = '<div>'+file.name+'</div><div class="progress"><div id="progress_'+ file.id +'"class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%">0%</div></div>'
$('#upload_modal_body').append(uploadFileProgressHtml)
// 生成新的记录
$sbzFile.val(file.name);
if (sbzUploadConf.autoUpload) {
uploader.upload();
}
});
// 当某个文件的分块在发送前触发,主要用来询问是否要添加附带参数,大文件在开起分片上传的前提下此事件可能会触发多次。
uploader.onUploadBeforeSend = function(obj, data) {
console.log("onUploadBeforeSend");
var file = obj.file;
data.md5 = file.md5 || '';
data.uid = file.uid;
data.bid=file.bid;
data.type=file.type;
data.docType=sbzUploadConf.docType;
};
// 上传中
uploader.on('uploadProgress', function(file, percentage) {
console.log('进度中', file, percentage)
getProgressBar(file, percentage, "FILE", "上传进度");
});
// 上传返回结果
uploader.on('uploadSuccess', function(file) {
var text = '已上传';
if (file.pass) {
text = "文件妙传功能,文件已上传。"
}
$('#' + file.id).find('p.state').text(text);
});
uploader.on('uploadError', function(file) {
$('#' + file.id).find('p.state').text('上传出错');
});
uploader.on('uploadComplete', function(file) {
console.log('uploadComplete')
// $("#common_upload_modal").hide();
sbz.Msg.success(file.name + " 上传完成");
$("#common_upload_title").html(file.name + ' 上传完成')
uploadCompleteCallback(file)
});
var uploadFlag = true;
// hky 进度条
function getProgressBar(file, percentage, id_Prefix, titleName) {
if(uploadFlag) {
$("#common_upload_modal").modal("toggle");
uploadFlag = false;
}
var value = (percentage * 100).toFixed(2);
var progressPercentage = value + '%';
$('#progress_'+ file.id).html(progressPercentage)
$('#progress_'+ file.id).attr('aria-valuenow', value)
$('#progress_'+ file.id).width(progressPercentage)
if(id_Prefix == 'MD5') {
$("#common_upload_title").html('文件:' + file.name + ' 处理中')
}else{
$("#common_upload_title").html('文件:' + file.name + ' 上传进度')
}
}
然后,把上传按钮的事件初始化
//上传按钮
$('#upload_btn').bind("click", function () {
sbzUploadConf.businessId = 'xxxxx';
console.info("sbzUploadConf.businessId=====" + sbzUploadConf.businessId);
uploader.reset();
$('.webuploader-element-invisible').click();
});
function onReleaseChange(refId) {
if (tableData.length) {
let data = docReleaseModal.tableData.find((item) => {
return item.refId === refId
});
docPropertiesModal.show(data,docReleaseTable);
docPropertiesTable.reload();
}
}
其中$(‘.webuploader-element-invisible’).click();就是webuploader插件生成的input标签的代码。也就是手动调了下,input file 标签的选择文件。
2.后端部分
校验文件是否上传过,可实现秒传。
@RequestMapping(value = "/checkFileMd5", method = RequestMethod.POST)
@ResponseBody
public Object checkFileMd5(String md5) throws IOException {
ResultVo result = null;
Object processingObj = stringRedisTemplate.opsForHash().get(UploadConst.FILE_UPLOAD_STATUS,
UploadConfig.getFileMd5(md5));
if (processingObj == null) {
result = new ResultVo(ResultStatus.NO_HAVE);
} else {
String processingStr = processingObj.toString();
boolean processing = Boolean.parseBoolean(processingStr);
String value = stringRedisTemplate.opsForValue().get(UploadConfig.getUploadRedisKey(md5));
if (processing) {
File t = new File(value);
if (t.exists()) {
result = new ResultVo(ResultStatus.IS_HAVE, value);
} else {
result = new ResultVo(ResultStatus.NO_HAVE);
}
} else {
List<String> missChunkList = new LinkedList<>();
if (value != null && value.length() > 0) {
File confFile = new File(value);
if (confFile.exists()) {
byte[] completeList = FileUtils.readFileToByteArray(confFile);
for (int i = 0; i < completeList.length; i++) {
if (completeList[i] != Byte.MAX_VALUE) {
missChunkList.add(i + "");
}
}
} else {
result = new ResultVo(ResultStatus.NO_HAVE);
}
}
result = new ResultVo<>(ResultStatus.ING_HAVE, missChunkList);
}
}
return result;
}
文件上传接口:
@RequestMapping(value = "/fileUpload", method = RequestMethod.POST)
@ResponseBody
public ResponseEntity fileUpload(MulitpartFileData param, HttpServletRequest request) {
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (isMultipart) {
SystemLogger.debug("上传文件start。");
try {
storageService.uploadFileByMappedByteBuffer(param);
} catch (IOException e) {
e.printStackTrace();
SystemLogger.error("文件上传失败" + param.toString(), e);
ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body("上传失败");
}
SystemLogger.debug("上传文件end。");
}
return ResponseEntity.ok("上传成功。");
}
先写这么多,简单做个记录,以后有空再补充…