基于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;
}
}
浙公网安备 33010602011771号