Copy import com.longxiang.utils.DateTimeUtil;
import com.longxiang.utils.constants.DateConstants;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.*;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
/**
* Author: Minchang Hsu (Caster)
* Date: 2022/12/13
* Comment:
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class AWSS3StorageService {
@Value("${custom.aws.bucketName}")
private String bucketName;
@Value("${custom.aws.baseFolder}")
private String baseFolder;
private final S3Client s3;
private String composeKey(String key){
return baseFolder + "/" + (StringUtils.isBlank(key) ? "" : key);
}
public ListObjectsResponse listObjects() {
return s3.listObjects(ListObjectsRequest.builder().bucket(bucketName).prefix(baseFolder).build());
}
public void deleteObject(String key) {
try {
s3.deleteObject(DeleteObjectRequest.builder().bucket(bucketName).key(composeKey(key)).build());
} catch (Exception e) {
e.printStackTrace();
log.error("Exception > delete object. key:{}, message:{}.", key, e.getMessage());
}
}
public void multipartUpload(String key, InputStream inputStream, Long splitSize) {
String keyName = composeKey(key);
long partSize = Objects.isNull(splitSize) ? 5 * 1024 * 1024l : splitSize.longValue(); // Set part size to 5 MB.
try {
CreateMultipartUploadRequest createMultipartUploadRequest = CreateMultipartUploadRequest.builder()
.bucket(bucketName)
.key(keyName)
.build();
CreateMultipartUploadResponse response = s3.createMultipartUpload(createMultipartUploadRequest);
String uploadId = response.uploadId();
List<CompletedPart> completedParts = new ArrayList<>();
log.warn("Multiple Part upload. key:{}, id:{}, upload start.", keyName, uploadId);
int index = 1;
byte[] buffer = new byte[(int) partSize];
int len;
while ((len = inputStream.read(buffer, 0, buffer.length)) > 0) {
InputStream targetStream;
if (len < buffer.length)
targetStream = new ByteArrayInputStream(buffer, 0, len);
else
targetStream = new ByteArrayInputStream(buffer);
{
// Upload all the different parts of the object
UploadPartRequest uploadPartRequest = UploadPartRequest.builder()
.bucket(bucketName)
.key(keyName)
.uploadId(uploadId)
.contentLength(Long.valueOf(len + ""))
.partNumber(index).build();
UploadPartResponse uploadPartResponse = s3.uploadPart(uploadPartRequest,
RequestBody.fromInputStream(targetStream, len));
completedParts.add(CompletedPart.builder().eTag(uploadPartResponse.eTag()).partNumber(index).build());
log.warn("Multiple Part upload. key:{}, eTag:{}", keyName, uploadPartResponse.eTag());
}
index++;
}
// Finally call completeMultipartUpload operation to tell S3 to merge all uploaded
// parts and finish the multipart operation.
CompletedMultipartUpload completedMultipartUpload = CompletedMultipartUpload.builder()
.parts(completedParts)
.build();
CompleteMultipartUploadRequest completeMultipartUploadRequest =
CompleteMultipartUploadRequest.builder()
.bucket(bucketName)
.key(keyName)
.uploadId(uploadId)
.multipartUpload(completedMultipartUpload)
.build();
s3.completeMultipartUpload(completeMultipartUploadRequest);
log.warn("Multiple Part upload. key:{}, id:{}, upload end.", keyName, uploadId);
} catch (Exception e) {
e.printStackTrace();
log.error("Exception > Multiple Part upload. key:{}, message:{}.", keyName, e.getMessage());
}
}
public void traceMultipartUploadProgressAPI(Boolean abortUpload, String key) {
try {
ListMultipartUploadsResponse response = s3.listMultipartUploads(ListMultipartUploadsRequest.builder().bucket(bucketName).build());
List<MultipartUpload> uploads = response.uploads();
if (StringUtils.isNotBlank(key) && abortUpload) {
uploads.stream().filter(o -> o.key().equals(composeKey(key))).findFirst().ifPresent(o -> abortMultipartUpload(o.key(), o.uploadId()));
} else {
uploads.stream().forEach(o -> {
log.warn("Initiated Date: {}, key:{}, " + "uploadId:{}",
DateTimeUtil.formatDate(Date.from(o.initiated()), DateConstants.YYYY_MM_DD_HH_mm_SS), o.key(), o.uploadId());
if (abortUpload)
abortMultipartUpload(o.key(), o.uploadId());
});
}
} catch (S3Exception s3Exception) {
s3Exception.printStackTrace();
log.error(s3Exception.getMessage());
}
}
/**
* abortMultipartUpload
* @param key
* @param uploadId
*/
private void abortMultipartUpload(String key, String uploadId) {
try {
s3.abortMultipartUpload(AbortMultipartUploadRequest.builder()
.bucket(bucketName)
.key(key)
// .expectedBucketOwner("xxxxxx") // 加了會錯, 不清楚這用途要幹嘛, 要再查看看
.uploadId(uploadId)
.build());
} catch (S3Exception s3Exception) {
log.warn("Unable to upload file, upload was aborted.");
s3Exception.printStackTrace();
}
}
}