前后端分离跨服务器文件上传,【原创】webuploader分片上传(前后端分离)

项目地址:

功能描述

1、webuploader是百度研发的上传组件,文档不是特别规整,但是也够用了。

2、前端使用官网的上传图片demo,在此基础上代码略微调整做分片。既可以上传图片也可以上传文件。文件超过分片大小才启用分片。

3、分片上传已做md5校验,达到秒传的效果。分片以后需要合并,可以先分片后合并,也可以边分片边合并,本示例采用的是边分片边合并的方案。

4、后端用springboot做框架搭建。springMVC做rest服务,开启跨域访问。

5、容器用springboot内置的tomcat插件,运行Application的main方法即可启动服务;

显示效果

04a2c632e5f075c7efa9291cdbebe39f.png

94328f43d96c17a2d06903cf8b90bcb4.png

a5788a2ba305484682b0dd0ee6a7e517.png

关键代码

前端

WebUploader.Uploader.register({

'name': 'webUploaderHookCommand',

'before-send-file': 'beforeSendFile',

"before-send": "beforeSend"

}, {

beforeSendFile: function(file) {

var task = new WebUploader.Deferred();

fileName = file.name;

fileSize = file.size;

(new WebUploader.Uploader()).md5File(file, 0, 10 * 1024 * 1024).progress(function(percentage) {}).then(function(val) {

fileMd5 = val;

var url = checkUrl;

var data = {

type: 0,

fileName: fileName,

fileMd5: fileMd5,

fileSize: fileSize

};

$.ajax({

type: "POST",

url: url,

data: data,

cache: false,

async: false, // 同步

timeout: 1000, // todo 超时的话,只能认为该分片未上传过

dataType: "json",

error: function(XMLHttpRequest, textStatus, errorThrown) {

file.statusText = 'server_error';

task.reject();

}

}).then(function(data, textStatus, jqXHR) {

if(data.rtn == 0) {

if(data.obj == 1) {

file.statusText = 'file_existed';

task.reject();

} else {

task.resolve();

}

} else {

task.reject();

}

});

});

return task.promise();

},

beforeSend: function(block) {

var task = new WebUploader.Deferred();

var url = checkUrl;

var data = {

type: 1,

fileName: fileName,

fileMd5: fileMd5,

chunk: block.chunk,

fileSize: block.end - block.start

};

$.ajax({

type: "POST",

url: url,

data: data,

cache: false,

async: false, // 同步

timeout: 1000, // todo 超时的话,只能认为该分片未上传过

dataType: "json"

}).then(function(data, textStatus, jqXHR) {

if(data.rtn == 0 && data.obj == 1) {

task.reject(); // 分片存在,则跳过上传

} else {

task.resolve();

}

});

this.owner.options.formData.fileMd5 = fileMd5;

this.owner.options.formData.chunkSize = chunkSize;

return task.promise();

}

});

// 实例化

uploader = WebUploader.create({

pick: {

id: '#filePicker',

label: '点击选择文件'

},

formData: {

uid: 123

},

dnd: '#dndArea', //指定文件拖拽的区域

paste: '#uploader', //指定监听paste事件的容器,如果不指定,不启用此功能。此功能为通过粘贴来添加截屏的图片。建议设置为document.body.

swf: '../plugins/webuploader/Uploader.swf',

chunked: true,

chunkSize: chunkSize,

chunkRetry: false,

threads: 1,

server: uploadUrl,

// runtimeOrder: 'flash',

// accept: {

// title: 'Images',

// extensions: 'gif,jpg,jpeg,bmp,png',

// mimeTypes: 'image/*'

// },

// 禁掉全局的拖拽功能。这样不会出现图片拖进页面的时候,把图片打开。

disableGlobalDnd: true,

fileNumLimit: 300 //限制多文件上传的个数

//fileSizeLimit: 200 * 1024 * 1024, // 限制所有文件的大小 200 M

//fileSingleSizeLimit: 50 * 1024 * 1024 // 限制单个文件的大小 50 M

});

后端

import java.io.File;

import java.io.IOException;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.stereotype.Service;

import org.springframework.web.multipart.MultipartFile;

import com.bear.upload.util.FileUtil;

import com.bear.upload.util.RETURN;

import com.bear.upload.vo.CheckMd5FileVO;

import com.bear.upload.vo.UploadVO;

@Service

public class ChunkUploadService {

private static Logger LOG = LoggerFactory.getLogger(ChunkUploadService.class);

@Value("${file.upload.path}")

private String UPLOAD_PATH;

private static final String Delimiter = "-";

/**

* 上传之前校验(整个文件、分片)

*

* @param md5FileVO

* @return

*/

public Object check(CheckMd5FileVO md5FileVO) {

Integer type = md5FileVO.getType();

Long chunk = md5FileVO.getChunk();

String fileName = md5FileVO.getFileName();

Long fileSize = md5FileVO.getFileSize();

if (type == 0) {// 未分片校验

String destfilePath = UPLOAD_PATH + File.separator + fileName;

File destFile = new File(destfilePath);

if (destFile.exists() && destFile.length() == fileSize) {

return RETURN.success("文件已存在,跳过", 1);

} else {

return RETURN.success("文件不存在", 0);

}

} else {// 分片校验

String fileMd5 = md5FileVO.getFileMd5();

String destFileDir = UPLOAD_PATH + File.separator + fileMd5;

String destFileName = chunk + Delimiter + fileName;

String destFilePath = destFileDir + File.separator + destFileName;

File destFile = new File(destFilePath);

if (destFile.exists() && destFile.length() == fileSize) {

return RETURN.success("分片已存在,跳过", 1);

} else {

return RETURN.success("分片不存在", 0);

}

}

}

/**

* 文件上传

*

* @param file

* @param uploadVO

* @param appVersion

* @return

*/

public Object upload(MultipartFile file, UploadVO uploadVO) {

Long chunk = uploadVO.getChunk();

if (chunk == null) {// 没有分片

return UnChunkUpload(file, uploadVO);

} else {// 分片

return ChunkUpload(file, uploadVO);

}

}

/**

* 分片上传

*

* @param file

* @param uploadVO

* @param appVersion

* @return

*/

public Object ChunkUpload(MultipartFile file, UploadVO uploadVO) {

String fileName = uploadVO.getName();

String fileMd5 = uploadVO.getFileMd5();

Long chunk = uploadVO.getChunk();// 当前片

Long chunks = uploadVO.getChunks();// 总共多少片

// 分片目录创建

String chunkDirPath = UPLOAD_PATH + File.separator + fileMd5;

File chunkDir = new File(chunkDirPath);

if (!chunkDir.exists()) {

chunkDir.mkdirs();

}

// 分片文件上传

String chunkFileName = chunk + Delimiter + fileName;

String chunkFilePath = chunkDir + File.separator + chunkFileName;

File chunkFile = new File(chunkFilePath);

try {

file.transferTo(chunkFile);

} catch (Exception e) {

LOG.error("分片上传出错", e);

return RETURN.fail("分片上传出错", 1);

}

// 合并分片

Long chunkSize = uploadVO.getChunkSize();

long seek = chunkSize * chunk;

String destFilePath = UPLOAD_PATH + File.separator + fileName;

File destFile = new File(destFilePath);

if (chunkFile.length() > 0) {

try {

FileUtil.randomAccessFile(chunkFile, destFile, seek);

} catch (IOException e) {

LOG.error("分片{}合并失败:{}", chunkFile.getName(), e.getMessage());

return RETURN.fail("分片合并失败", 1);

}

}

if (chunk == chunks - 1) {

// 删除分片文件夹

FileUtil.deleteDirectory(chunkDirPath);

return RETURN.success("上传成功", 1);

} else {

return RETURN.fail("上传中...", 1);

}

}

/**

* 未分片上传

*

* @param file

* @param uploadVO

* @param appVersion

* @return

*/

public Object UnChunkUpload(MultipartFile file, UploadVO uploadVO) {

String fileName = uploadVO.getName();

// String fileMd5 = uploadVO.getFileMd5();

// 文件上传

File destFile = new File(UPLOAD_PATH + File.separator + fileName);

if (file != null && !file.isEmpty()) {

// 上传目录

File fileDir = new File(UPLOAD_PATH);

if (!fileDir.exists()) {

fileDir.mkdirs();

}

if (destFile.exists()) {

destFile.delete();

}

try {

file.transferTo(destFile);

return RETURN.success("上传成功", 0);

} catch (Exception e) {

LOG.error("文件上传出错", e);

return RETURN.fail("文件上传出错", 0);

}

}

return RETURN.fail("上传失败", 0);

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值