S3上传文件

发布时间 2023-10-22 15:46:34作者: yydssc

<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<version>2.20.144</version>
</dependency>

 

 

 

public static Map<String, Object> filePartUploadThread(CommonsMultipartFile file, String dirName, String fileName) {
ensureBucket();
Date date = new Date();
String beginTime = date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds();
Map<String, Object> resultMap = new HashMap();
// 创建一个可重用固定线程数的线程池。若同一时间线程数大于10,则多余线程会放入队列中依次执行
ExecutorService executorService = Executors.newFixedThreadPool(10);
String uploadDir = "";//目录名
if (!StringUtil.isEmpty(dirName)) {
uploadDir = dirName.replaceAll("\\\\", "/") + "/";
}
// 完整的文件名
LOGGER.info("file.getOriginalFilename()==" + file.getOriginalFilename());
// 保存文件路径名称
String uploadPath = uploadDir + fileName;
int fileSuffixIndex = file.getOriginalFilename().lastIndexOf('.');
if (fileSuffixIndex >= 0) {
String fileSuffix = file.getOriginalFilename().substring(fileSuffixIndex);
uploadPath = uploadPath + fileSuffix;
}
SysLog.print("文件切块开始时间==========>" + System.currentTimeMillis());
String uploadId = AwsS3Upload.claimUploadId(bucketName, uploadPath);
try {
// 设置每块为 5M(除最后一个分块以外,其他的分块大小都要大于5MB)
// final long partSize = Integer.parseInt(PART_SIZE) * 1024 * 1024L;
final long partSize = Integer.parseInt("5") * 1024 * 1024L;
long position = 0;
int partNumber = 1;
int totalNum = 0;
while (position < file.getSize()) {
long partSizeRemaining = Math.min(partSize, file.getSize() - position);
executorService.execute(new AwsS3Upload(file, position, partSizeRemaining, partNumber, uploadId, uploadPath, bucketName));
position += partSizeRemaining;
partNumber++;
totalNum++;
}
/**
* 等待所有分片完毕
*/
// 关闭线程池(线程池不马上关闭),执行以前提交的任务,但不接受新任务。
executorService.shutdown();

// 如果关闭后所有任务都已完成,则返回 true。
while (!executorService.isTerminated()) {
try {
// 用于等待子线程结束,再继续执行下面的代码
executorService.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
System.out.println("异常信息:" + e);
}
}
System.out.println("文件切块结束时间==========>" + System.currentTimeMillis());

/**
* partETags(上传块的ETag与块编号(PartNumber)的组合) 如果校验与之前计算的分块大小不同,则抛出异常
*/
if (AwsS3Upload.partETags.size() != totalNum) {
throw new IllegalStateException("分块大小与文件所计算的分块大小不一致");
} else {
LOGGER.info("将要上传的文件名 " + uploadPath + "\n");

}

/* 列出文件所有的分块清单并打印到日志中,该方法仅仅作为输出使用*/
AwsS3Upload.listAllParts(uploadId);
System.out.println("文件分块上传开始时间==========>" + System.currentTimeMillis());

/* 完成分块上传 */
CompleteMultipartUploadResponse completeMultipartUploadResponse = AwsS3Upload.completeMultipartUpload(uploadId);
System.out.println("文件分块上传结束时间==========>" + System.currentTimeMillis());
Date date2 = new Date();
String endTime = date2.getHours() + ":" + date2.getMinutes() + ":" + date2.getSeconds();
System.out.println(beginTime + "========" + endTime);
// 返回上传文件的URL地址
resultMap.put("status", true);
resultMap.put("msg", completeMultipartUploadResponse.location());
return resultMap;
} catch (Exception e) {
SysLog.print("上传失败!", e);
resultMap.put("status", false);
resultMap.put("msg", "上传失败!");
return resultMap;
} finally {
AwsS3Upload.partETags.clear();
}

}

 

 

package com.auxgroup.tc.common.utils;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.model.*;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
*
*/
public class AwsS3Upload implements Runnable {
private MultipartFile localFile;
private long startPos;
private long partSizeRemaining;
private int partNumber;
private String uploadId;
private static String key;
private static String bucketName;

/**
* The constant partETags.
*/
// 新建一个List保存每个分块上传后的ETag和PartNumber
protected static List<CompletedPart> partETags = Collections.synchronizedList(new ArrayList<CompletedPart>());

private static final Logger LOGGER = LoggerFactory.getLogger(AwsS3Upload.class);


/**
* 创建构造方法
*
* @param localFile 要上传的文件
* @param partNumber the part number
* @param uploadId 作为块的标识
* @param key 上传到OSS后的文件名
* @param bucketName the bucket name
*/
public AwsS3Upload(MultipartFile localFile, long startPos,long partSizeRemaining, int partNumber, String uploadId, String key, String bucketName) {
this.localFile = localFile;
this.startPos=startPos;
this.partSizeRemaining = partSizeRemaining;
this.partNumber = partNumber;
this.uploadId = uploadId;
AwsS3Upload.key = key;
AwsS3Upload.bucketName = bucketName;
}

/**
* 分块上传核心方法(将文件分成按照每个5M分成N个块,并加入到一个list集合中)
*/
@Override
public void run() {
InputStream instream = null;
try {
// 获取文件流
instream = localFile.getInputStream();
long count = instream.skip(startPos);
// 创建UploadPartRequest,上传分块
UploadPartRequest uploadRequest = UploadPartRequest.builder()
.bucket(bucketName)
.key(key)
.uploadId(uploadId)
.partNumber(partNumber)
.contentLength(partSizeRemaining)
.build();

UploadPartResponse uploadResponse = AwsS3Utils.initS3Client().uploadPart(uploadRequest,
RequestBody.fromInputStream(instream, partSizeRemaining));


synchronized (partETags) {
// 将返回的PartETag保存到List中。
partETags.add(CompletedPart.builder()
.partNumber(partNumber)
.eTag(uploadResponse.eTag())
.build());
}
} catch (Exception e) {
LOGGER.error("异常-----------------", e.getMessage());
} finally {
if (instream != null) {
try {
// 关闭文件流
instream.close();
} catch (IOException e) {
LOGGER.error("异常-----------------", e.getMessage());
}
}
}
}

/**
* 初始化分块上传事件并生成uploadID,用来作为区分分块上传事件的唯一标识
*
* @param bucketName the bucket name
* @param key the key
* @return string
*/
protected static String claimUploadId(String bucketName, String key) {
CreateMultipartUploadRequest createRequest = CreateMultipartUploadRequest.builder()
.bucket(bucketName)
.key(key)
.build();
CreateMultipartUploadResponse createResponse = AwsS3Utils.initS3Client().createMultipartUpload(createRequest);
String uploadId = createResponse.uploadId();
return uploadId;
}

/**
* 将文件分块进行升序排序并执行文件上传。
*
* @param uploadId the upload id
*/
protected static CompleteMultipartUploadResponse completeMultipartUpload(String uploadId) {
// 将文件分块按照升序排序
partETags.sort(Comparator.comparingInt(CompletedPart::partNumber));

// 完成分片上传
CompleteMultipartUploadRequest completeRequest = CompleteMultipartUploadRequest.builder()
.bucket(bucketName)
.key(key)
.uploadId(uploadId)
.multipartUpload(CompletedMultipartUpload.builder()
.parts(partETags)
.build())
.build();

CompleteMultipartUploadResponse completeResponse = AwsS3Utils.initS3Client().completeMultipartUpload(completeRequest);
System.out.println("分片上传已完成。对象 URL:" + completeResponse.location());
return completeResponse;

}

/**
* 列出文件所有分块的清单
*
* @param uploadId the upload id
*/
protected static void listAllParts(String uploadId) {
ListPartsRequest listPartsRequest = ListPartsRequest.builder().bucket(bucketName)
.key(key).uploadId(uploadId).build();

ListPartsResponse listPartsResponse = AwsS3Utils.initS3Client().listParts(listPartsRequest);
List<Part> parts = listPartsResponse.parts();

for (Part part : parts) {
LOGGER.info("分块编号 " + part.partNumber() + ", ETag=" + part.eTag());
}

}
}