0
点赞
收藏
分享

微信扫一扫

Minio实现大文件切片上传

日月同辉9908 2024-05-28 阅读 42

大体思路就是前端根据文件名生成MD5编码,再将大文件按100M一块切成若干小片(Minio允许最小分片为5M),给每一片赋上序号(currentPiece)后依次调用接口上传。后端拿到数据后在redis里创建一个list存放已上传的片,再全部上传完成后由Minio进行合并并将地址返回给前端。

文件上传接口

    /**
     * 大文件切片上传
     */
    @PostMapping("/uploadFileChunk")
    public ResultMoudel uploadFileChunk( @RequestBody MultipartFileWrapper fileChunk ){
        try{
            Date date = new Date();
            String md5=fileChunk.getMd5();
            BoundListOperations files= redisTemplate.boundListOps(md5);
            List<Integer> list=files.range(0,-1);//拿出所有值
            if (CollectionUtils.isEmpty(list)){
                //如果是新上传的 创建redis对象
                files.expire(12, TimeUnit.HOURS);
                files.leftPush(null);
            }
            //如果已上传过 跳过
            if (list.contains(fileChunk.getCurrentPiece())){
                return new ResultMoudel().success("");
            }
            BigFile bigFile= ossTemplate.putBigFile(fileChunk);
            //将结果存入redis
            files.leftPush(fileChunk.getCurrentPiece());
            if (!"continue".equals(bigFile.getTransFlag())) {
                //文件传输完毕, 删除当前key
                redisTemplate.delete(md5);
                return new ResultMoudel<>().success(bigFile.getLink());
            }
            Date date1 = new Date();
            System.out.println(Thread.currentThread()+"文件上传花费了" + (date1.getTime() - date.getTime()));
        } catch (Exception exception) {
            //文件
            exception.printStackTrace();
            return new ResultMoudel().error(fileChunk.getCurrentPiece());
        }
        return new ResultMoudel().success("");
    }

对接Minio的文件上传实现


    public BigFile putBigFile(MultipartFileWrapper bigPartFile) {
        try {
            InputStream inputStream = bigPartFile.getCurrentFile().getInputStream();
            Map headers = new HashMap();
            PutObjectArgs putObjectArgs = (PutObjectArgs)((Builder)((Builder)((Builder)PutObjectArgs.builder().object(bigPartFile.getMd5().concat("/") + bigPartFile.getCurrentPiece())).headers(headers)).bucket(this.ossProperties.getTempBucketName())).stream(inputStream, (long)inputStream.available(), -1L).contentType("application/octet-stream").build();
            this.minioClient.putObject(putObjectArgs);
            if (this.isFinish(bigPartFile.getMd5(), bigPartFile.getTotalPiece())) {
                BigFile bigFile = this.mergeFile(bigPartFile.getTotalPiece(), bigPartFile.getMd5(), bigPartFile.getFileName());
                this.deleteTempFile(bigPartFile.getTotalPiece(), bigPartFile.getMd5());
                return bigFile;
            } else {
                return BigFile.builder().transFlag("continue").build();
            }
        } catch (Throwable var6) {
            throw var6;
        }
    }

    private boolean isFinish(String md5, int totalPieces) throws Exception {
        Iterable<Result<Item>> results = this.minioClient.listObjects((ListObjectsArgs)((io.minio.ListObjectsArgs.Builder)ListObjectsArgs.builder().bucket(this.ossProperties.getTempBucketName())).prefix(md5.concat("/")).build());
        Set<String> objectNames = Sets.newHashSet();
        Iterator var5 = results.iterator();

        while(var5.hasNext()) {
            Result<Item> item = (Result)var5.next();
            objectNames.add(((Item)item.get()).objectName());
        }

        return objectNames.size() == totalPieces;
    }

    private void deleteTempFile(int totalPieces, String md5) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        try {
            List<DeleteObject> delObjects = (List)Stream.iterate(0, (i) -> {
                return i + 1;
            }).limit((long)totalPieces).map((i) -> {
                return new DeleteObject(md5.concat("/").concat(Integer.toString(i)));
            }).collect(Collectors.toList());
            Iterable<Result<DeleteError>> results = this.minioClient.removeObjects((RemoveObjectsArgs)((io.minio.RemoveObjectsArgs.Builder)RemoveObjectsArgs.builder().bucket(this.ossProperties.getTempBucketName())).objects(delObjects).build());
            Iterator var5 = results.iterator();

            while(var5.hasNext()) {
                Result<DeleteError> result = (Result)var5.next();
                DeleteError error = (DeleteError)result.get();
                System.out.println("delete files " + error.objectName() + " " + error.message());
            }

        } catch (Throwable var8) {
            throw var8;
        }
    }

 查看上传进度条


    @PostMapping("selectChunks")
    public ResultMoudel selectChunks(@RequestParam String md5){
        BoundListOperations files=redisTemplate.boundListOps(md5);
        List range = files.range(0, -1);
        return new ResultMoudel().success(range.stream().filter(Objects::nonNull));
    }
举报

相关推荐

0 条评论