当前位置:   article > 正文

spring boot实现大文件上传【分片上传】插件(x-file-storage),同时支持本地、FTP、SFTP、阿里云 OSS、腾讯云 COS、MinIO、 Amazon S3等

x-file-storage

这篇文章 主要说一下 前端 分片后 传给后端 利用 插件(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);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

下面的代码 就是 为了让 上面截图提到的 代码 只初始化一次

    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 目前发现是 是不能设置的 
    
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

如果上面这段代码 在一个大文件上传的时候 多次初始化 就会导致 每次上传上来的分片数据 都会
创建一个新得文件夹 存放起来 比如你上传了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;
        }


    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87

大家如果有更好的初始化一次得解决办法 可以留言 学习一下

而且 每个用户相互不影响 初始化只针对当前上传得文件夹有效

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/正经夜光杯/article/detail/902229
推荐阅读
相关标签
  

闽ICP备14008679号