赞
踩
这篇文章 主要说一下 前端 分片后 传给后端 利用 插件(x-file-storage)实现 大文件上传 方案
插件(x-file-storage) 具体这个插件怎么使用 简单的文件上传 看下面的这篇博客 有详细说明
博客地址:
https://blog.csdn.net/Drug_/article/details/137794530
如果大家没用过 x-file-storage 这个插件 建议先看一下 上面得这个博客 再来用这个大文件上传
因为这个博客里没有讲解 引入依赖 配置 那些东西
下面我直接分享 大文件上传的代码 这个插件的配置 等等信息 参考上面博客地址
先给大家 看一下插件源码里 提供的分片上传的 demo
但是 他提供的例子 不太适合 前后端 分离开发 需要根据他的例子 改
下面 以我的理解 说一下例子中 哪里不合理
下面是我写的方案 只测试了 本地 大文件上传 没问题 代码应该还存在细节问题 大家请参考使用 如果有更好的方案 也可以留言分享给我 我再补充 博客
控制器
@ApiOperation(value = "大文件上传")
@PostMapping("uploadBig")
public R uploadBig(@RequestParam("file") MultipartFile file, //分片文件
@RequestParam("chunkNumber") int chunkNumber, //分片数
@RequestParam("totalChunks") int totalChunks, //分片总数
@RequestParam("filename") String filename //文件名
){
Map<String, Objects> fileInfo = filesUtil.uploadFileBig(file, "dmt" + LoginUserInfoHelper.getTenantId(),chunkNumber,totalChunks,filename);
return R.data(fileInfo);
}
下面的代码 就是 为了让 上面截图提到的 代码 只初始化一次
private static FileInfo sharedObject; // 共享的对象
private static FileStorageService fileStorageService; // 共享的对象
//这有个疑问 如果多个用户同时 上传 会不会公用一个对象
// 如果同时公用一个对象 那这个地方会存在文件 有可能 文件名 会相互覆盖 目前没验证
// synchronized 加锁 因为 我发现前端请求太快 有并发if 判断会失效 所以就加锁
private synchronized boolean initiateMultipartUpload(String fileDir,String name){
if(sharedObject!=null){
return true;
}
fileStorageService = this.init();
sharedObject = fileStorageService
.initiateMultipartUpload()
// .setPlatform(getFilesystemType())
.setPath(generateFilePath(fileDir))
.setOriginalFilename(name)
.setSaveFilename(getFileName() + "." + getFileExtensionWithDot(Objects.requireNonNull(name)))
.init();
return true;
//setUploadId 这个值 分片 很重要 不传 随机生成 这个值
// 是为了 分片的数据 是不是存放在同一文件夹里 分片表(file_part_detail)可以自定义设置
// 直接在 .init().setUploadId(); 设置
//但是 文件存储表(file_detail) 这个setUploadId 目前发现是 是不能设置的
}
如果上面这段代码 在一个大文件上传的时候 多次初始化 就会导致 每次上传上来的分片数据 都会
创建一个新得文件夹 存放起来 比如你上传了50次 分片数据 他就会创建50个文件夹
这样 他正执行合并 数据得时候 就会合并失败!
初始化多次 会创建多个文件夹 就是setUploadId() 这个方法 在起作用 你可以给他设置一个值
比如 setUploadId(“tmp”) 临时目录 但是 文件存储表(file_detail) 这个setUploadId 目前发现是 是不能设置的 所以还是会出现多个文件夹 所以我认为最好得解决方案就是 保证 一个文件在上传得过程中 只初始化一次
uploadFileBig() 上传方法
public Map<String, Objects> uploadFileBig(MultipartFile file2, String fileDir, int partNumber2, int countNumber, String name) {
if (StringUtils.isEmpty(fileDir)) {
fileDir = "files";
}
// 判断是否需要初始化共享对象
if (sharedObject == null) {
initiateMultipartUpload(fileDir,name); // 第一次请求到达时初始化对象
}
MultipartUploadSupportInfo supportInfo = fileStorageService.isSupportMultipartUpload();
if (!supportInfo.getIsSupport()) {
throw new ErpRuntimeException("此存储类型不支持分片上传!");
}
log.info("手动分片上传文件初始化成功:{}", sharedObject);
FilePartInfo filePartInfo = fileStorageService
.uploadPart(sharedObject, partNumber2, file2, (long) file2.getSize())
.setProgressListener(new ProgressListener() {
@Override
public void start() {
System.out.println("分片 " + partNumber2 + " 上传开始");
}
@Override
public void progress(long progressSize, Long allSize) {
if (allSize == null) {
System.out.println("分片 " + partNumber2 + " 已上传 " + progressSize + " 总大小未知");
} else {
System.out.println("分片 " + partNumber2 + " 已上传 " + progressSize + " 总大小"
+ allSize + " " + (progressSize * 10000 / allSize * 0.01) + "%");
}
}
@Override
public void finish() {
System.out.println("分片 " + partNumber2 + " 上传结束");
log.error("分片 " + partNumber2 + " 上传结束");
}
})
.setHashCalculatorMd5()
.setHashCalculatorSha256()
.upload();
log.info("手动分片上传-分片上传成功:{}", filePartInfo);
if (partNumber2 == countNumber) {
fileStorageService.completeMultipartUpload(sharedObject)
.setProgressListener(new ProgressListener() {
@Override
public void start() {
System.out.println("文件合并开始");
}
@Override
public void progress(long progressSize, Long allSize) {
if (allSize == null) {
System.out.println("文件已合并 " + progressSize + " 总大小未知");
} else {
System.out.println("文件已合并 " + progressSize + " 总大小" + allSize + " "
+ (progressSize * 10000 / allSize * 0.01) + "%");
}
}
@Override
public void finish() {
System.out.println("文件合并结束");
}
})
.complete();
log.info("手动分片上传文件完成成功:{}", sharedObject);
Map map = JSON.parseObject(JSON.toJSONString(sharedObject), Map.class);
sharedObject=null;
return map;
} else {
Map map = JSON.parseObject(JSON.toJSONString(filePartInfo), Map.class);
return map;
}
}
大家如果有更好的初始化一次得解决办法 可以留言 学习一下
而且 每个用户相互不影响 初始化只针对当前上传得文件夹有效
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。