Springboot Minio最新版大文件上传
超详细的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();
}
}
}
测试结果可以看视频,不明白也可以看开头的视频,讲的非常详细!
好了这篇就到这里了,希望对你有帮助!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!