首先在pom文件中添加依赖:
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.5.3</version>
</dependency>
在MinIO-8.5.3版本中 MinioClient中调用方法已经从本身调用转换成了其中的私有属性MinioAsyncClient完成异步调用。因此继承本身的MinioClient无法调用S3Base中的方法,
需要继承MinioAsyncClient去调用。
public class PearlMinioClient extends MinioAsyncClient {
protected PearlMinioClient(MinioAsyncClient client) {
super(client);
}
/**
* 创建分片上传请求
*
* @param bucketName 存储桶
* @param region 区域
* @param objectName 对象名
* @param headers 消息头
* @param extraQueryParams 额外查询参数
*/
@Override
public CompletableFuture<CreateMultipartUploadResponse> createMultipartUploadAsync(String bucketName, String region, String objectName, Multimap<String, String> headers, Multimap<String, String> extraQueryParams) throws InsufficientDataException, InternalException, InvalidKeyException, IOException, NoSuchAlgorithmException, XmlParserException {
return super.createMultipartUploadAsync(bucketName, region, objectName, headers, extraQueryParams);
}
/**
* 完成分片上传,执行合并文件
*
* @param bucketName 存储桶
* @param region 区域
* @param objectName 对象名
* @param uploadId 上传ID
* @param parts 分片
* @param extraHeaders 额外消息头
* @param extraQueryParams 额外查询参数
*/
@Override
public CompletableFuture<ObjectWriteResponse> completeMultipartUploadAsync(String bucketName, String region, String objectName, String uploadId, Part[] parts, Multimap<String, String> extraHeaders, Multimap<String, String> extraQueryParams) throws NoSuchAlgorithmException, InsufficientDataException, IOException, InvalidKeyException, XmlParserException, InternalException {
return super.completeMultipartUploadAsync(bucketName, region, objectName, uploadId, parts, extraHeaders, extraQueryParams);
}
/**
* 查询分片数据
*
* @param bucketName 存储桶
* @param region 区域
* @param objectName 对象名
* @param uploadId 上传ID
* @param extraHeaders 额外消息头
* @param extraQueryParams 额外查询参数
*/
public CompletableFuture<ListPartsResponse> listMultipart(String bucketName, String region, String objectName, Integer maxParts, Integer partNumberMarker, String uploadId, Multimap<String, String> extraHeaders, Multimap<String, String> extraQueryParams) throws NoSuchAlgorithmException, InsufficientDataException, IOException, InvalidKeyException, ServerException, XmlParserException, ErrorResponseException, InternalException, InvalidResponseException {
return super.listPartsAsync(bucketName, region, objectName, maxParts, partNumberMarker, uploadId, extraHeaders, extraQueryParams);
}
}
有这三个方法之后就比较简单了。
首先确定逻辑 应该是有一个文件标识上传之后,判断之前是否有上传的过程 有的话返回查询过的数据,没有的话就初始化一个分片任务 ,完成上传之后进行合并即可。
Service层,判断之前是否有上传
public TaskInfoDTO getPartInfo(String identifier) throws Exception {
MultipartFileInfo multipartFileInfo = multipartFileDao.selectByIdentifier(identifier);
if (multipartFileInfo==null){
return null;
}
String bucketName = multipartFileInfo.getBucketName();
String objectName = multipartFileInfo.getFilePath();
TaskInfoDTO taskInfo = new TaskInfoDTO(true, getPath(bucketName, objectName), MultipartFileDTO.convertFromEntity(multipartFileInfo));
if (multipartFileInfo.getIsComplete()==1){
return taskInfo;
}else {
ListPartsResponse result = pearlMinioClient.listMultipart(bucketName, null, objectName, 10000, 0, multipartFileInfo.getUploadId(), null, null).get();
List<Part> partList = result.result().partList();
taskInfo.getMultipartFileDTO().setExitPartList(MultipartFileDTO.exchangeExitPartList(partList));
taskInfo.setFinished(false);
}
return taskInfo;
}
获取上传的地址 给前端去直接将文件上传到minIO
@Override
public String preUrl(String identifier,int partNumber) throws Exception {
MultipartFileInfo multipartFileInfo = multipartFileDao.selectByIdentifier(identifier);
if (multipartFileInfo == null) {
throw new RuntimeException("分片任务不存在");
}
Map<String, String> params = new HashMap<>();
params.put("partNumber", String.valueOf(partNumber));
params.put("uploadId", multipartFileInfo.getUploadId());
return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
.bucket(multipartFileInfo.getBucketName()).object(multipartFileInfo.getFilePath())
.method(Method.PUT).expiry(expiry).extraQueryParams(params).build());
}
如果之前的判断之前是否上传的记录返回为null 那么就去初始化一个任务
@Override
public TaskInfoDTO createMultipart(String fileIdentifier,String bucketName, String fileName, long chunkSize,long totalSize) throws Exception {
//判断有无该桶
bucketName = getBuckets(bucketName) ? bucketName : "";
if(Strings.isBlank(bucketName)){
bucketName = MinioProperties.MINIO_BUCKET_NAME;
}else if(!getBuckets(bucketName)){
throw new RuntimeException("不存在该桶");
}
String suffix = fileName.substring(fileName.lastIndexOf(".")+1);
String key = com.boppod.iplatform.common.core.utils.StringUtils.format("{}/{}.{}", DateUtils.datePath(), IdUtils.randomUUID(), suffix);
CreateMultipartUploadResponse response = pearlMinioClient.createMultipartUploadAsync(bucketName, null, key, null, null).get();
String uploadId = response.result().uploadId();
Map<String, String> reqParams = new HashMap<>();
reqParams.put("uploadId", uploadId);
for (int i = 1; i <= chunkSize; i++) {
reqParams.put("partNumber", String.valueOf(i));
}
int chunkNum = (int) Math.ceil(totalSize * 1.0 / chunkSize);
//将信息存入数据库中
return new TaskInfoDTO(false, getPath(bucketName, key), MultipartFileDTO.convertFromEntity(multipartfileInfo));
}
上传完成之后合并分片任务即可
@Override
public boolean completeMultipart(String identifier) {
try {
Part[] parts = new Part[1000];
MultipartFileInfo multipartFileInfo = multipartFileDao.selectByIdentifier(identifier);
if (multipartFileInfo==null){
throw new RuntimeException("分片任务不存在");
}
String objectName = multipartFileInfo.getFilePath();
String bucketName = multipartFileInfo.getBucketName();
String uploadId = multipartFileInfo.getUploadId();
CompletableFuture<ListPartsResponse> future = pearlMinioClient.listMultipart(bucketName, null, objectName, 1000, 0, uploadId, null, null);
ListPartsResponse response = future.get();
List<Part> partList = response.result().partList();
if (partList.size()!= multipartFileInfo.getChunkNum()){
// 已上传分块数量与记录中的数量不对应,不能合并分块
throw new RuntimeException("分片缺失,请重新上传");
}
int partNum=1;
for (int i = 0; i < partList.size(); i++) {
parts[partNum-1]=new Part(partNum,partList.get(i).etag());
partNum++;
}
pearlMinioClient.completeMultipartUploadAsync(bucketName, null, objectName, uploadId, parts, null, null);
multipartFileDao.uploadByIdetifier(identifier);
}catch (Exception e){
return false;
}
return true;
}
参考文章:
Gitee上的minio-upload-api ;
csdn上云烟成雨TD的MinIO教学。
minio-upload-api有现成的前端代码可以测试。