Springboot Minio最新版大文件上传

2023-12-15 18:50:48

超详细的SpringBoot Minio大文件上传业务,看了这个视频,你绝对不会后悔

完整代码地址:GitHub - dufGIT/minio-file: 资源文件中心?

本章节主要讲Minio的文件上传以及大文件上传的功能,小文件上传比较简单,大文件上传需要前端计算整个文件的md5,然后协商下一个分片多少兆,之后就按那个去分,分完调用上传接口,上传以后合并分片文件就好了,稍微复杂了一丢丢,但是呢我会用大白话讲出来让您觉得简单的。

pom包,咱们这个是最新版,

        <!-- 操作minio的java客户端-->
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>8.5.7</version>
        </dependency>

可能会报okhttp的错,Unsupported OkHttp library found. Must use okhttp >= 4.8.1

此时需要排除minio本身的okhttp,再下载个别的版本okhttp包就可以了,代码如下:

 <!-- 操作minio的java客户端-->
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>8.5.7</version>
            <exclusions>
                <exclusion>
                    <groupId>com.squareup.okhttp3</groupId>
                    <artifactId>okhttp</artifactId>
                </exclusion>
            </exclusions>
        </dependency>


     <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>4.10.0</version>
        </dependency>

application配置文件

redis:
  host: localhost
  port: 6379
  database: 0
  password:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/fileresource
    password: 123456
    username: root
    driver-class-name: com.mysql.jdbc.Driver

#minio配置
minio:
  access-key: 3qUk0XPgTKLxx8RR
  secret-key:  joUG6ShKxJNZtjqdzrnpO373czSfIiRP
  url: http://localhost:9008  #访问地址
  bucket-name: formal-file
  bucket-name-slice: slice-file

minio的配置类:

@Data
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinioConfig {
    private String accessKey;

    private String secretKey;

    private String url;

    private String bucketName;

    private String bucketNameSlice;

    @Bean
    public MinioClient minioClient() {
        return MinioClient.builder()
                .endpoint(url)
                .credentials(accessKey, secretKey)
                .build();
    }
}

文件上传也包含大文件上传(进行分片)还有完整文件上传(小文件),我就都在一个接口里写都过参数来判断处理不同的逻辑,如果是分片上传的化因为接口需要调用多次,某些功能的性能或者是多次调库的原因,所以需要提取出来一两个接口进行初始化,以及检查文件是否上传多次的判断。

Controller如下:

包含文件上传以及检查文件是否上传以及文件初始化接口。还有相应的参数校验。

@Validated
@RestController
public class FileUploadController {

    @Resource
    private IFileUploadProcess fileUploadProcess;
    @Resource
    private TResourceService resourceFileService;


    /**
     * 文件上传
     */
    @PostMapping("/upload/file")
    public Result uploadFile(@Valid @ModelAttribute UploadFileReq uploadFileReq) {
        return fileUploadProcess.uploadFile(uploadFileReq);
    }

    /**
     * 检查是否上传过文件
     *
     * @return true:已上传过,false:没有上传过
     */
    @GetMapping("/isExist/file")
    public Result checkIsUploadFile(@NotBlank(message = "文件md5不能为空!")
                                            String md5) {
        try {
            Boolean isExistFile = resourceFileService.checkIsExistFile(md5);
            return Result.success(isExistFile);
        } catch (Exception e) {
            return Result.failed();
        }
    }

    /**
     * 文件初始化
     * 1.创建桶
     * 2.将分片索引放入到redis中
     * 3.将分片以及对应基本信息先存储到资源附件中(resourceFile)
     */
    @PostMapping("/init/fileData")
    public Result initFileData(@RequestBody @Valid InitSliceDataReq initSliceDataReq) {
        return fileUploadProcess.initFileData(initSliceDataReq);
    }
}

对应需要的两个service接口,IFileUploadProcess和TResourceService

IFileUploadProcess:关于文件上传的流程接口,包括文件上传方法定义、文件初始化方法定义

public interface IFileUploadProcess {
    /**
     * 文件上传
     * 1.完整文件直接上传,上传完更新库的文件信息(resourceFile)
     * 2.分片上传需要判断是否全部都上传完,全部上传完则合并数据,
     * 合并后删除原来的分片数据,并更新库的文件信息(resourceFile)。
     *
     * @initSliceDataReq 初始化分片需要的参数
     */
    Result uploadFile(UploadFileReq uploadFileReq);

    /**
     * 初始化切片操作
     * 1.没有桶创建桶
     * 2.如果是分片缓存,后续分片上传需要
     * 3.先插入一条资源附件表
     *
     * @initSliceDataReq 初始化分片需要的参数
     */
    Result initFileData(InitSliceDataReq initSliceDataReq);
}

TResourceService:资源服务接口,主要处理文件资源落库处理,包括插入文件、检查文件是否存在库表、文件上传完毕则更新数据库为已上传。

public interface TResourceService {
    /**
     * 新增ResourceFile数据
     *
     * @param resourceFile 实例对象
     * @return 实例对象
     */
    Boolean insertFile(TResourceFile resourceFile);

    Boolean checkIsExistFile(String md5);

    /**
     * 更新数据库文件为已上传
     *
     * @param md5          文件的md5
     * @return 实例对象
     */
    Boolean updateFileUploadState(
            String md5);

}

IFileUploadProcess实现类:FileUploadProcessImpl

uploadFile:文件上传流程,业务如下:

  • 判断文件是否是完整上传,如果是则直接调用完整上传接口业务,然后上传完更新数据库文件已上传即可。
  • 如果是分片则直接调用分为文件上传接口业务,分片文件上传完毕进行合并minio文件到正式的minio桶,文件合并完毕则删除minio临时分片的桶,上传完更新数据库文件已上传即可。

initFileData:文件初始化流程:业务如下:

  • 判断是否有minio桶,没有先创建桶,有则跳过。
  • 根据总切片数量初始化切片放入缓存,为后续文件分片上传进行索引判断。
  • 初始化文件信息入库,状态为未上传。
@Slf4j
@Service
public class FileUploadProcessImpl implements IFileUploadProcess {

    @Resource
    private IFileUploadBusiness fileUploadBusiness;
    @Resource
    private TResourceService resourceFileService;
    @Resource
    private MinioConfig minioConfig;


    @Override
    public Result uploadFile(UploadFileReq uploadFileReq) {
        //--------------------文件-------------------------------
        MultipartFile file = uploadFileReq.getFile();
        //--------------------资源-------------------------------
        String md5 = uploadFileReq.getMd5();
        Integer totalIndex = uploadFileReq.getTotalIndex();
        Integer sliceIndex = uploadFileReq.getSliceIndex();

        String fullMd5Name = md5 + "." + uploadFileReq.getFileSuffix();

        // 文件上传-不分片
        if (uploadFileReq.getIsSlice() == 0) {
            log.debug("完整文件上传处理-------------");
            Boolean isWholeUpload = fileUploadBusiness.uploadFile(fullMd5Name, file);
            if (!isWholeUpload) {
                // 上传失败
                return Result.failed(Constants.ResponseCode.UPLOAD_FILE_FAILED.getCode(),
                        Constants.ResponseCode.UPLOAD_FILE_FAILED.getMsg());
            }
            // 更新已上传状态信息到库里
            Boolean isUpdateSucc = resourceFileService.updateFileUploadState(md5);
            if (!isUpdateSucc) return Result.failed(Constants.ResponseCode.UPLOAD_UPDATEDB_FAILED.getCode(),
                    Constants.ResponseCode.UPLOAD_UPDATEDB_FAILED.getMsg());
            return Result.success();
        }

        // 文件上传--分片
        if (uploadFileReq.getIsSlice() == 1) {
            log.debug("分片文件上传处理-------------");
            // 分片上传
            Result sliceResult = fileUploadBusiness.uploadSliceFile(md5, totalIndex, sliceIndex, file);
            if (sliceResult != null) {
                String code = sliceResult.getCode();
                String sliceIndexStr = String.valueOf(sliceResult.getData());
                // 完成所有的分片上传
                if (code.equals(Constants.ResponseCode.SUCCESS.getCode())
                        && "-1".equals(sliceIndexStr)) {
                    log.debug("已完成分片文件上传处理-------------");
                    // 合并文件
                    Boolean composeSuccess = fileUploadBusiness.composeFile(md5,fullMd5Name, totalIndex);

                    // 文件合并失败提示
                    if (!composeSuccess) {
                        return Result.failed(Constants.ResponseCode.UPLOAD_COMPOSE_FAILED.getCode(),
                                Constants.ResponseCode.UPLOAD_COMPOSE_FAILED.getMsg());
                    }

                    // 更新已上传状态信息到库里
                    Boolean isUpdateSucc = resourceFileService.updateFileUploadState(md5);
                    if (!isUpdateSucc) return Result.failed(Constants.ResponseCode.UPLOAD_UPDATEDB_FAILED.getCode(),
                            Constants.ResponseCode.UPLOAD_UPDATEDB_FAILED.getMsg());

                    // TODO 是否开一个线程单独处理它
                    // 删除minio所有的分片文件
                    fileUploadBusiness.delSliceFile(md5, totalIndex);
                }
            }
            return sliceResult;
        }
        return Result.success();

    }

    /**
     * 初始化文件信息操作
     */
    @Override
    public Result initFileData(InitSliceDataReq initSliceDataReq) {
        Integer isSlice = initSliceDataReq.getIsSlice();
        // 判断是否有minio桶,没有先创建桶
        Boolean isCreateBucket = fileUploadBusiness.createFileBucket();
        if (!isCreateBucket) return Result.failed(Constants.ResponseCode.UPLOAD_BUCKET_FAILED.getCode(),
                Constants.ResponseCode.UPLOAD_BUCKET_FAILED.getMsg());

        // 初始化切片放入缓存
        if (isSlice == 1) {
            Boolean isInRedis = fileUploadBusiness.sliceInRedis(initSliceDataReq.getMd5(), initSliceDataReq.getTotalSlice());
            if (!isInRedis) return Result.failed(Constants.ResponseCode.UPLOAD_INIT_SLICE_FAILED.getCode(),
                    Constants.ResponseCode.UPLOAD_INIT_SLICE_FAILED.getMsg());
        }

        // 文件名称
        String fileName = initSliceDataReq.getOriginalFileName();
        // 是否存在文件后缀
        Integer isExistStr = fileName.lastIndexOf(".");
        // 获取文件后缀
        String fileType = isExistStr != -1 ? fileName.substring(isExistStr + 1) : "";
        // 判断是否已存库
        Boolean isExist = resourceFileService.checkIsExistFile(initSliceDataReq.getMd5());
        if (!isExist) {
            // 上传前先存储库
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            TResourceFile resourceFile = TResourceFile.builder()
                    .isUploaded(0)
                    .uuid(uuid)
                    .minioMd5(initSliceDataReq.getMd5())
                    .minioBucket(minioConfig.getBucketName())
                    .totalSlice(isSlice == 0 ? 0 : initSliceDataReq.getTotalSlice())
                    .originalFileName(initSliceDataReq.getOriginalFileName())
                    .sliceFileSize(isSlice == 0 ? 0 : initSliceDataReq.getSliceFileSize())
                    .fileSize(initSliceDataReq.getFileSize())
                    .createdTime(new Date()).build();
            Boolean isFileInfoDB = resourceFileService.insertFile(resourceFile);
            if (!isFileInfoDB) return Result.failed();
        }
        log.info("初始化成功!|initFileData|参数:initSliceDataReq:{}", initSliceDataReq);
        return Result.success();
    }
}

?IFileUploadBusiness:文件上传业务接口,

  • uploadFile:完整文件上传定义方法
  • uploadSliceFile:分片文件上传定义方法
  • composeFile:分片文件合并定义方法
  • delSliceFile:删除minio分片文件定义方法
  • createFileBucket:初始化时创建桶定义方法
  • sliceInRedis:初始化分片入redis的定义方法
public interface IFileUploadBusiness {

    /**
     * 完整文件上传
     */
    Boolean uploadFile(String objectName, MultipartFile file);

    /**
     * 分片文件上传
     * 1.去缓存取出对应索引信息,判断此次给的索引信息是否相同,不相同则告知
     * 2.上传分片文件以后则删除缓存数据
     * 3.全部分片上传完后data数据返回-1
     *
     * @param objectName  可以当文件名这里用md5
     * @param totalPieces 总分片数量
     * @param sliceIndex  当前传过来的分片索引
     * @param file        文件
     */
    Result uploadSliceFile(String objectName, Integer totalPieces, Integer sliceIndex, MultipartFile file);

    /**
     * 分片文件合并
     *
     * @param objectName  可以当文件名这里用md5
     * @param totalPieces 总分片数量
     */
    Boolean composeFile(String objectName,String fullObjectName, Integer totalPieces);

    /**
     * 删除minio分片文件
     *
     * @param objectName  可以当文件名这里用md5
     * @param totalPieces 总分片数量
     * @return Boolean ture成功,false是失败
     */
    Boolean delSliceFile(String objectName, Integer totalPieces);

    /**
     * 初始化时创建桶
     *
     * @return Boolean ture成功,false是失败
     */
    Boolean createFileBucket();

    /**
     * 初始化分片入库
     *
     * @return Boolean ture成功,false是失败
     */
    Boolean sliceInRedis(String md5, Integer totalSlice);

}

IFileUploadBusiness实现类:FileUploadBusinessImpl关于文件上传的具体业务代码。

  • ?uploadFile:完整文件上传直接调用minio工具类将参数传入过去上传即可。
  • uploadSliceFile:分片上传,去数据库取出分片与当前前端传过来的分片索引对比是否一致,一致则上传当前分片文件,不一致则反馈,当传过来的分片索引与总索引一致则认为上传完毕返回个标识即可。
  • composeFile:合并分片文件,取出minio里的所有的临时分片数据对象,调用minio工具类将参数传过去就可以合并了。
  • delSliceFile:删除临时分片桶,调用minio工具类把所有的分片文件删除即可。
  • createFileBucket:创建桶操作,也是需要调用minio工具类创建桶。
  • sliceInRedis:按业务规定将分片索引依次放入redis集合中。
@Slf4j
@Service
public class FileUploadBusinessImpl implements IFileUploadBusiness {


    @Resource
    private MinioUtils minioUtils;

    @Resource
    private RedisDao redisDao;

    @Resource
    private MinioConfig minioConfig;

    /**
     * 完整文件上传
     */
    @Override
    public Boolean uploadFile(String objectName, MultipartFile file) {
        //  文件上传
        return minioUtils.uploadFile(minioConfig.getBucketName(), objectName, null, file);
    }

    /**
     * 把文件块上传到分片桶
     *
     * @return Integer 要上传的分片数,-1是上传完成
     */
    @Override
    public Result uploadSliceFile(String objectName, Integer totalPieces, Integer sliceIndex, MultipartFile file) {
        // 分片上传完毕标志
        Integer isUploaded = -1;
        // 无需合并标志
        Integer isCompose = -2;

        Object sliceIndexRedis = redisDao.indexValue(objectName, 0);
        String sliceIndexStr = String.valueOf(sliceIndexRedis);
        if (!"".equals(sliceIndexRedis) && null != sliceIndexRedis) {
            Integer sliceIndexRedisInt = Integer.parseInt(sliceIndexStr);
            // 索引不一致,要求一致
            if (sliceIndexRedisInt != sliceIndex) {
                return Result.failed(Constants.ResponseCode.UPLOAD_INDEX_UNMATCHED.getCode(),
                        Constants.ResponseCode.UPLOAD_INDEX_UNMATCHED.getMsg(), sliceIndexRedisInt);
            }
        } else {
            log.debug("缓存中无此分片信息,可能已经全部上传完毕,或没有初始化分片");
            // 无分片,可能上传完了,所以不需要合并
            return Result.success(isCompose);
        }
        // 上传分片文件
        Boolean isUpload = minioUtils.uploadFile(minioConfig.getBucketNameSlice(), objectName, sliceIndex, file);
        if (isUpload) {

            // 上传完成删除缓存中的分片
            // TODO 删除判断
            boolean isRemove = redisDao.remove(objectName, sliceIndexStr, 1);
            if (sliceIndex < totalPieces - 1) {
                return Result.success(sliceIndex + 1);
            }
            return Result.success(isUploaded);
        }
        // 上传失败
        return Result.failed(Constants.ResponseCode.UPLOAD_FILE_FAILED.getCode(),
                Constants.ResponseCode.UPLOAD_FILE_FAILED.getMsg(), sliceIndex);
    }

    /**
     * 分片合并
     *
     * @return Boolean ture成功,false是失败
     */
    @Override
    public Boolean composeFile(String objectName,String fullObjectName, Integer totalPieces) {
        // 完成上传从缓存目录合并迁移到正式目录
        List<ComposeSource> sourceObjectList = Stream.iterate(0, i -> ++i)
                .limit(totalPieces)
                .map(i -> ComposeSource.builder()
                        .bucket(minioConfig.getBucketNameSlice())
                        .object(objectName.concat("/").concat(Integer.toString(i)))
                        .build())
                .collect(Collectors.toList());
        log.debug("文件合并|composeFile|参数objectName:{},fullObjectName:{},totalPieces:{}", objectName,fullObjectName, totalPieces);
        // 合并操作
        Boolean isCompose = minioUtils.composeFile(minioConfig.getBucketName(), fullObjectName, sourceObjectList);
        return isCompose;
    }


    /**
     * 删除minio分片文件
     *
     * @return Boolean ture成功,false是失败
     */
    @Override
    public Boolean delSliceFile(String objectName, Integer totalPieces) {
        // 删除所有的临时分片文件
        List<DeleteObject> delObjects = Stream.iterate(0, i -> ++i)
                .limit(totalPieces)
                .map(i -> new DeleteObject(objectName.concat("/").concat(Integer.toString(i))))
                .collect(Collectors.toList());
        Boolean isDel = minioUtils.removeFiles(minioConfig.getBucketNameSlice(), delObjects);
        return isDel;
    }

    /**
     * 初始化时创建桶
     *
     * @return Boolean ture成功,false是失败
     */
    @Override
    public Boolean createFileBucket() {
        boolean sliceBucket = minioUtils.createBucket(minioConfig.getBucketNameSlice());
        boolean fileBucket = minioUtils.createBucket(minioConfig.getBucketName());
        if (sliceBucket && fileBucket) {
            return true;
        }
        return false;
    }


    @Override
    public Boolean sliceInRedis(String md5, Integer totalSlice) {
        if (!redisDao.hasKey(md5)) {
            for (int i = 0; i < totalSlice; i++) {
                redisDao.rpush(md5, String.valueOf(i));
            }
        }
        return true;
    }

}

TResourceService的实现类:TResourceServiceImpl,该实现类主要是对于库表的增删改查,

  • insertFile:初始化时插入文件、
  • checkIsExistFile:检查库表里是否有文件
  • updateFileUploadState:更新文件表为已上传。
@Slf4j
@Service
public class TResourceServiceImpl implements TResourceService {
    @Resource
    private TResourceMapper tResourceFileMapper;

    @Override
    public Boolean insertFile(TResourceFile resourceFile) {
        try {
            resourceFile.setCreatedTime(new Date());
            tResourceFileMapper.insert(resourceFile);
            return true;
        } catch (Exception e) {
            log.error("保存tResourceFile异常|参数:{}|{}", resourceFile, e);
            return false;
        }
    }

    @Override
    public Boolean checkIsExistFile(String md5) {
        QueryWrapper<TResourceFile> wrapper = new QueryWrapper<>();
        wrapper.eq("minio_md5", md5);
        Long existNum = tResourceFileMapper.selectCount(wrapper);
        if (existNum > 0) {
            return true;
        }
        return false;
    }

    @Override
    public Boolean updateFileUploadState(String md5) {
        try {
            // 设置需要更改的参数
            UpdateWrapper<TResourceFile> wrapper = new UpdateWrapper<>();
            wrapper.eq("minio_md5", md5)
                    .set("is_uploaded", 1);
            log.debug("更新已上传文件状态到DB|updateFileUploadState|参数:resourceUuid:{},md5:{}", md5);
            tResourceFileMapper.update(new TResourceFile(), wrapper);
            return true;
        } catch (Exception e) {
            log.error("更新tResourceFile异常|参数:{},{}|{}", md5, e);
            return false;
        }
    }

}

minio工具类:

@Slf4j
@Component
public class MinioUtils {
    @Autowired
    private MinioClient minioClient;


    /**
     * 文件上传/文件分块上传
     *
     * @param bucketName 桶名称
     * @param objectName 对象名称
     * @param sliceIndex 分片索引
     * @param file       文件
     */
    public Boolean uploadFile(String bucketName, String objectName, Integer sliceIndex, MultipartFile file) {
        try {
            if (sliceIndex != null) {
                objectName = objectName.concat("/").concat(Integer.toString(sliceIndex));
            }
            // 写入文件
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .stream(file.getInputStream(), file.getSize(), -1)
                    .contentType(file.getContentType())
                    .build());
            log.debug("上传到minio文件|uploadFile|参数:bucketName:{},objectName:{},sliceIndex:{}"
                    , bucketName, objectName, sliceIndex);
            return true;
        } catch (Exception e) {
            log.error("文件上传到Minio异常|参数:bucketName:{},objectName:{},sliceIndex:{}|异常:{}", bucketName, objectName, sliceIndex, e);
            return false;
        }
    }

    /**
     * 创建桶,放文件使用
     *
     * @param bucketName 桶名称
     */
    public Boolean createBucket(String bucketName) {
        try {
            if (!minioClient.bucketExists(
                    BucketExistsArgs.builder().bucket(bucketName).build())) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            }
            return true;
        } catch (Exception e) {
            log.error("Minio创建桶异常!|参数:bucketName:{}|异常:{}", bucketName, e);
            return false;
        }
    }

    /**
     * 文件合并
     *
     * @param bucketName       桶名称
     * @param objectName       对象名称
     * @param sourceObjectList 源文件分片数据
     */
    public Boolean composeFile(String bucketName, String objectName, List<ComposeSource> sourceObjectList) {
        // 合并操作
        try {
            ObjectWriteResponse response = minioClient.composeObject(
                    ComposeObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .sources(sourceObjectList)
                            .build());
            return true;
        } catch (Exception e) {
            log.error("Minio文件按合并异常!|参数:bucketName:{},objectName:{}|异常:{}", bucketName, objectName, e);
            return false;
        }
    }

    /**
     * 多个文件删除
     *
     * @param bucketName 桶名称
     */
    public Boolean removeFiles(String bucketName, List<DeleteObject> delObjects) {
        try {
            Iterable<Result<DeleteError>> results =
                    minioClient.removeObjects(
                            RemoveObjectsArgs.builder().bucket(bucketName).objects(delObjects).build());
            boolean isFlag = true;
            for (Result<DeleteError> result : results) {
                DeleteError error = result.get();
                log.error("Error in deleting object {} | {}", error.objectName(), error.message());
                isFlag = false;
            }
            return isFlag;
        } catch (Exception e) {
            log.error("Minio多个文件删除异常!|参数:bucketName:{},objectName:{}|异常:{}", bucketName, e);
            return false;
        }
    }

单元测试:包括计算文件md5以及初始化,分片上传,完整文件上传的测试

@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = FileResourceApplication.class)
public class UploadTest {
    @Resource
    private IFileUploadProcess fileUploadProcess;

    // 获取文件流的md5
    @Test
    public void getWholeFileMd5() {
        // 创建File对象
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream("D:\\teach-split\\image.png");
            String md5Hex = DigestUtils.md5Hex(inputStream);
            log.info("获取文件的md5:{}", md5Hex);
            inputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // TODO 先初始化——分片文件版本
    @Test
    public void init_slice_file() {
        InitSliceDataReq initSliceDataReq = InitSliceDataReq.builder()
                .md5("880576b5104a0ce4931c2a5c8c547000")
                .isSlice(1)
                .totalSlice(5)
                .originalFileName("test.vedio.mp4")
                .sliceFileSize(9814662.00)
                .fileSize(49073311.00)
                .build();

        Result result = fileUploadProcess.initFileData(initSliceDataReq);
        log.info("初始化结果--分片文件版本:{}", result);
    }

    // TODO 再上传文件--分片文件
    @Test
    public void slice_upload_file() {
        try {
            // 读取本地文件
            byte[] fileContent = FileUtils.readFileToByteArray(new File("D:\\teach-split\\video.mp4.4"));
            // 读取本地文件
            // 转换为MultiPartFile对象
            MultipartFile multipartFile = new MockMultipartFile("880576b5104a0ce4931c2a5c8c547000", "test.vedio.mp4",
                    "application/octet-stream", fileContent);
            UploadFileReq uploadFileReq = UploadFileReq.builder()
                    .md5("880576b5104a0ce4931c2a5c8c547000")
                    .fileSuffix("mp4")
                    .isSlice(1)
                    .totalIndex(5)
                    .sliceIndex(4)
                    .file(multipartFile).build();
            Result result = fileUploadProcess.uploadFile(uploadFileReq);
            log.info("文件上传--分片上传结果:{}", result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // TODO 先初始化——完整文件版本
    @Test
    public void init_whole_file() {
        InitSliceDataReq initSliceDataReq = InitSliceDataReq.builder()
                .md5("a9500aa2091875f3d02a9b84ae1ab712")
                .isSlice(0)
                .originalFileName("image.png")
                .fileSize(1540702.00)
                .build();
        Result result = fileUploadProcess.initFileData(initSliceDataReq);
        log.info("初始化结果--完整文件版本:{}", result);
    }

    // TODO 再上传文件--完整文件
    @Test
    public void whole_upload_file() {
        try {
            // 读取本地文件
            byte[] fileContent = FileUtils.readFileToByteArray(new File("D:\\teach-split\\image.png"));
            // 读取本地文件
            // 转换为MultiPartFile对象
            MultipartFile multipartFile = new MockMultipartFile("a9500aa2091875f3d02a9b84ae1ab712", "image.png",
                    "multipart/form-data", fileContent);

            UploadFileReq uploadFileReq = UploadFileReq.builder()
                    .md5("a9500aa2091875f3d02a9b84ae1ab712")
                    .isSlice(0)
                    .fileSuffix("png")
                    .file(multipartFile).build();
            Result result = fileUploadProcess.uploadFile(uploadFileReq);
            log.info("文件上传--完整文件上传结果:{}", result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

测试结果可以看视频,不明白也可以看开头的视频,讲的非常详细!

好了这篇就到这里了,希望对你有帮助!

文章来源:https://blog.csdn.net/dfBeautifulLive/article/details/134885476
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。