基于software.amazon.awssdk对接七牛云实现分片大文件上传下载

1.引入pom

<!--  AWS SDK for Java 2.x  -->
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>s3</artifactId>
            <exclusions>
                <!-- 将基于 Netty 的 HTTP 客户端从类路径中移除 -->
                <exclusion>
                    <groupId>software.amazon.awssdk</groupId>
                    <artifactId>netty-nio-client</artifactId>
                </exclusion>
                <!-- 将基于 CRT 的 HTTP 客户端从类路径中移除 -->
                <exclusion>
                    <groupId>software.amazon.awssdk</groupId>
                    <artifactId>aws-crt-client</artifactId>
                </exclusion>
                <!-- 将基于 Apache 的 HTTP 客户端从类路径中移除 -->
                <exclusion>
                    <groupId>software.amazon.awssdk</groupId>
                    <artifactId>apache-client</artifactId>
                </exclusion>
                <!-- 将配置基于 URL 连接的 HTTP 客户端从类路径中移除 -->
                <exclusion>
                    <groupId>software.amazon.awssdk</groupId>
                    <artifactId>url-connection-client</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- 使用AWS基于 CRT 的 S3 客户端 -->
        <dependency>
            <groupId>software.amazon.awssdk.crt</groupId>
            <artifactId>aws-crt</artifactId>
            <version>0.29.13</version>
        </dependency>

        <!-- 基于 AWS CRT 的 S3 客户端的性能增强的 S3 传输管理器 -->
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>s3-transfer-manager</artifactId>
        </dependency>

<!-- 添加 Apache HTTP 客户端实现 -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
<version>
2.25.15</version>
</dependency>
 

2.编写接口 QiniuMultipartUploadExample

/**
 * 七牛云分片上传示例
 * 使用S3协议实现大文件分片上传
 */
public class QiniuMultipartUploadExample {
    private static final Logger log = LoggerFactory.getLogger(QiniuMultipartUploadExample.class);

    private final S3Client s3Client;
    private final String bucketName;

    /**
     * 构造函数
     * @param accessKey 七牛云AccessKey
     * @param secretKey 七牛云SecretKey
     * @param endpoint 七牛云Endpoint
     * @param bucketName 存储空间名称
     */
    public QiniuMultipartUploadExample(String accessKey, String secretKey, String endpoint, String bucketName) {
        this.bucketName = bucketName;

        // 创建S3客户端
        this.s3Client = S3Client.builder()
                .endpointOverride(URI.create(endpoint))
                .region(Region.of("z1"))  // 七牛云华北区域使用 z1
                .credentialsProvider(StaticCredentialsProvider.create(
                        AwsBasicCredentials.create(accessKey, secretKey)))
                .build();
    }
    /**
     * 执行分片上传
     * @param file 要上传的文件
     * @param objectKey 对象键(文件名)
     * @return 上传后的文件URL
     */
    public String uploadMultipart(File file, String objectKey,ProgressCallback progressCallback) {
        // 分片大小:5MB
        long partSize = 5 * 1024 * 1024L;
        long fileLength = file.length();
        long partCount = (fileLength + partSize - 1) / partSize;

        // 初始化分片上传
        CreateMultipartUploadRequest createMultipartUploadRequest = CreateMultipartUploadRequest.builder()
                .bucket(bucketName)
                .key(objectKey)
                .build();
        CreateMultipartUploadResponse createMultipartUploadResponse = s3Client.createMultipartUpload(createMultipartUploadRequest);
        String uploadId = createMultipartUploadResponse.uploadId();
        UploadProgressListener progressListener = new UploadProgressListener(progressCallback);

        // 上传分片
        List<CompletedPart> completedParts = new ArrayList<>();
        try (FileInputStream fileInputStream = new FileInputStream(file)) {
            long uploadedBytes = 0;
            for (int i = 0; i < partCount; i++) {
                progressListener.updateProgress(uploadedBytes, fileLength);
                long startPos = i * partSize;
                long curPartSize = Math.min(partSize, fileLength - startPos);
                byte[] partData = new byte[(int) curPartSize];
                fileInputStream.read(partData);
                uploadedBytes += curPartSize;
                if (progressCallback != null) {
                    progressCallback.onProgress(uploadedBytes, fileLength);
                }
                UploadPartRequest uploadPartRequest = UploadPartRequest.builder()
                        .bucket(bucketName)
                        .key(objectKey)
                        .uploadId(uploadId)
                        .partNumber(i + 1)
                        .build();

                UploadPartResponse uploadPartResponse = s3Client.uploadPart(uploadPartRequest, RequestBody.fromBytes(partData));
                completedParts.add(CompletedPart.builder()
                        .partNumber(i + 1)
                        .eTag(uploadPartResponse.eTag())
                        .build());

                log.info("Part {} uploaded successfully", i + 1);
            }
        } catch (IOException e) {
            log.error("Error during multipart upload", e);
            // 发生错误时中止上传
            AbortMultipartUploadRequest abortMultipartUploadRequest = AbortMultipartUploadRequest.builder()
                    .bucket(bucketName)
                    .key(objectKey)
                    .uploadId(uploadId)
                    .build();
            s3Client.abortMultipartUpload(abortMultipartUploadRequest);
            throw new RuntimeException("Multipart upload failed", e);
        }

        // 完成分片上传
        CompletedMultipartUpload completedMultipartUpload = CompletedMultipartUpload.builder()
                .parts(completedParts)
                .build();

        CompleteMultipartUploadRequest completeMultipartUploadRequest = CompleteMultipartUploadRequest.builder()
                .bucket(bucketName)
                .key(objectKey)
                .uploadId(uploadId)
                .multipartUpload(completedMultipartUpload)
                .build();

        CompleteMultipartUploadResponse result = s3Client.completeMultipartUpload(completeMultipartUploadRequest);

        log.info("Multipart upload completed successfully");
        return result.location();
    }

    /**
     * 使用示例
     */
    public static void main(String[] args) {
        // 配置参数
        String accessKey = "xxxx";
        String secretKey = "xxxx";
        String endpoint = "https://s3-cn-north-1.qiniucs.com"; // 七牛云华北区域 endpoint
        String bucketName = "xxxx";

        // 创建上传实例
        QiniuMultipartUploadExample uploader = new QiniuMultipartUploadExample(
                accessKey, secretKey, endpoint, bucketName);

        // 执行上传
        try {
            //本地文件路径
            File file = new File("D:\\基于ktgmes改造的sotoken认证.rar");
            String objectKey = "2024/1.rar";
            String fileUrl =uploader.uploadMultipart(file, objectKey, (uploaded, total) -> {
                // 计算进度百分比
                double progress = (double) uploaded / total * 100;
                // 更新前端进度条
                System.out.printf("上传进度: %.2f%%\n", progress);
            });
            System.out.println("File uploaded successfully. URL: " + fileUrl);
        } catch (Exception e) {
            System.err.println("Upload failed: " + e.getMessage());
        }
    }
}

 2.ProgressCallback

@FunctionalInterface
public interface ProgressCallback {
    void onProgress(long uploadedBytes, long totalBytes);
}

3.UploadProgressInfo

@Data
public class UploadProgressInfo {
private String fileName; // 文件名
private long uploadedBytes; // 已上传字节数
private long totalBytes; // 总字节数
private double percent; // 上传百分比
private String status; // 上传状态:uploading/success/error
private String message; // 状态信息
}
4.UploadProgressListener
public class UploadProgressListener {
private long bytesTransferred = 0;
private long totalBytes = 0;
private final ProgressCallback callback;

public UploadProgressListener(ProgressCallback callback) {
this.callback = callback;
}

public void updateProgress(long bytes, long total) {
this.bytesTransferred = bytes;
this.totalBytes = total;
if (callback != null) {
callback.onProgress(bytesTransferred, totalBytes);
}
}

public double getProgress() {
return totalBytes == 0 ? 0 : (double) bytesTransferred / totalBytes * 100;
}
}
posted @ 2025-03-26 16:37  Fyy发大财  阅读(134)  评论(0)    收藏  举报