From f1208474f771a1c233d7425c8ed13fbaa0d521ac Mon Sep 17 00:00:00 2001 From: baoshiwei <baoshiwei@shlanbao.cn> Date: 星期三, 12 三月 2025 09:35:13 +0800 Subject: [PATCH] Merge remote-tracking branch 'origin/5.X' into 5.X --- ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java | 162 ++++++++++------------------------------------------- 1 files changed, 31 insertions(+), 131 deletions(-) diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java index 5e300da..e3b20dd 100644 --- a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java @@ -9,21 +9,18 @@ import org.dromara.common.oss.constant.OssConstant; import org.dromara.common.oss.entity.UploadResult; import org.dromara.common.oss.enumd.AccessPolicyType; -import org.dromara.common.oss.enumd.PolicyType; import org.dromara.common.oss.exception.OssException; import org.dromara.common.oss.properties.OssProperties; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.core.ResponseInputStream; -import software.amazon.awssdk.core.async.AsyncRequestBody; import software.amazon.awssdk.core.async.AsyncResponseTransformer; import software.amazon.awssdk.core.async.BlockingInputStreamAsyncRequestBody; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3AsyncClient; import software.amazon.awssdk.services.s3.S3Configuration; +import software.amazon.awssdk.services.s3.crt.S3CrtHttpConfiguration; import software.amazon.awssdk.services.s3.model.GetObjectResponse; -import software.amazon.awssdk.services.s3.model.NoSuchBucketException; -import software.amazon.awssdk.services.s3.model.S3Exception; import software.amazon.awssdk.services.s3.presigner.S3Presigner; import software.amazon.awssdk.transfer.s3.S3TransferManager; import software.amazon.awssdk.transfer.s3.model.*; @@ -35,6 +32,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.time.Duration; +import java.util.function.Consumer; /** * S3 瀛樺偍鍗忚 鎵�鏈夊吋瀹筍3鍗忚鐨勪簯鍘傚晢鍧囨敮鎸� @@ -83,10 +81,10 @@ StaticCredentialsProvider credentialsProvider = StaticCredentialsProvider.create( AwsBasicCredentials.create(properties.getAccessKey(), properties.getSecretKey())); - //MinIO 浣跨敤 HTTPS 闄愬埗浣跨敤鍩熷悕璁块棶锛岀珯鐐瑰~鍩熷悕銆傞渶瑕佸惎鐢ㄨ矾寰勬牱寮忚闂� + // MinIO 浣跨敤 HTTPS 闄愬埗浣跨敤鍩熷悕璁块棶锛岀珯鐐瑰~鍩熷悕銆傞渶瑕佸惎鐢ㄨ矾寰勬牱寮忚闂� boolean isStyle = !StringUtils.containsAny(properties.getEndpoint(), OssConstant.CLOUD_SERVICE); - //鍒涘缓AWS鍩轰簬 CRT 鐨� S3 瀹㈡埛绔� + // 鍒涘缓AWS鍩轰簬 CRT 鐨� S3 瀹㈡埛绔� this.client = S3AsyncClient.crtBuilder() .credentialsProvider(credentialsProvider) .endpointOverride(URI.create(getEndpoint())) @@ -95,6 +93,9 @@ .minimumPartSizeInBytes(10 * 1025 * 1024L) .checksumValidationEnabled(false) .forcePathStyle(isStyle) + .httpConfiguration(S3CrtHttpConfiguration.builder() + .connectionTimeout(Duration.ofSeconds(60)) // 璁剧疆杩炴帴瓒呮椂 + .build()) .build(); //AWS鍩轰簬 CRT 鐨� S3 AsyncClient 瀹炰緥鐢ㄤ綔 S3 浼犺緭绠$悊鍣ㄧ殑搴曞眰瀹㈡埛绔� @@ -112,50 +113,11 @@ .serviceConfiguration(config) .build(); - // 鍒涘缓瀛樺偍妗� - createBucket(); } catch (Exception e) { if (e instanceof OssException) { throw e; } throw new OssException("閰嶇疆閿欒! 璇锋鏌ョ郴缁熼厤缃�:[" + e.getMessage() + "]"); - } - } - - /** - * 鍚屾鍒涘缓瀛樺偍妗� - * 濡傛灉瀛樺偍妗朵笉瀛樺湪锛屼細杩涜鍒涘缓锛涘鏋滃瓨鍌ㄦ《瀛樺湪锛屼笉鎵ц浠讳綍鎿嶄綔 - * - * @throws OssException 褰撳垱寤哄瓨鍌ㄦ《鏃跺彂鐢熷紓甯告椂鎶涘嚭 - */ - public void createBucket() { - String bucketName = properties.getBucketName(); - try { - // 灏濊瘯鑾峰彇瀛樺偍妗剁殑淇℃伅 - client.headBucket( - x -> x.bucket(bucketName) - .build()) - .join(); - } catch (Exception ex) { - if (ex.getCause() instanceof NoSuchBucketException) { - try { - // 瀛樺偍妗朵笉瀛樺湪锛屽皾璇曞垱寤哄瓨鍌ㄦ《 - client.createBucket( - x -> x.bucket(bucketName)) - .join(); - - // 璁剧疆瀛樺偍妗剁殑璁块棶绛栫暐锛圔ucket Policy锛� - client.putBucketPolicy( - x -> x.bucket(bucketName) - .policy(getPolicy(bucketName, getAccessPolicy().getPolicyType()))) - .join(); - } catch (S3Exception e) { - // 瀛樺偍妗跺垱寤烘垨绛栫暐璁剧疆澶辫触 - throw new OssException("鍒涘缓Bucket澶辫触, 璇锋牳瀵归厤缃俊鎭�:[" + e.getMessage() + "]"); - } - } else { - throw new OssException("鍒ゆ柇Bucket鏄惁瀛樺湪澶辫触锛岃鏍稿閰嶇疆淇℃伅:[" + ex.getMessage() + "]"); - } } } @@ -178,7 +140,9 @@ .key(key) .contentMD5(StringUtils.isNotEmpty(md5Digest) ? md5Digest : null) .contentType(contentType) - .acl(getAccessPolicy().getObjectCannedACL()) + // 鐢ㄤ簬璁剧疆瀵硅薄鐨勮闂帶鍒跺垪琛紙ACL锛夈�備笉鍚屼簯鍘傚晢瀵笰CL鐨勬敮鎸佸拰瀹炵幇鏂瑰紡鏈夋墍涓嶅悓锛� + // 鍥犳鏍规嵁鍏蜂綋鐨勪簯鏈嶅姟鎻愪緵鍟嗭紝浣犲彲鑳介渶瑕佽繘琛屼笉鍚岀殑閰嶇疆锛堣嚜琛屽紑鍚紝闃块噷浜戞湁acl鏉冮檺閰嶇疆锛岃吘璁簯娌℃湁acl鏉冮檺閰嶇疆锛� + //.acl(getAccessPolicy().getObjectCannedACL()) .build()) .addTransferListener(LoggingTransferListener.create()) .source(filePath).build()); @@ -215,7 +179,10 @@ } try { // 鍒涘缓寮傛璇锋眰浣擄紙length濡傛灉涓虹┖浼氭姤閿欙級 - BlockingInputStreamAsyncRequestBody body = AsyncRequestBody.forBlockingInputStream(length); + BlockingInputStreamAsyncRequestBody body = BlockingInputStreamAsyncRequestBody.builder() + .contentLength(length) + .subscribeTimeout(Duration.ofSeconds(30)) + .build(); // 浣跨敤 transferManager 杩涜涓婁紶 Upload upload = transferManager.upload( @@ -224,7 +191,9 @@ y -> y.bucket(properties.getBucketName()) .key(key) .contentType(contentType) - .acl(getAccessPolicy().getObjectCannedACL()) + // 鐢ㄤ簬璁剧疆瀵硅薄鐨勮闂帶鍒跺垪琛紙ACL锛夈�備笉鍚屼簯鍘傚晢瀵笰CL鐨勬敮鎸佸拰瀹炵幇鏂瑰紡鏈夋墍涓嶅悓锛� + // 鍥犳鏍规嵁鍏蜂綋鐨勪簯鏈嶅姟鎻愪緵鍟嗭紝浣犲彲鑳介渶瑕佽繘琛屼笉鍚岀殑閰嶇疆锛堣嚜琛屽紑鍚紝闃块噷浜戞湁acl鏉冮檺閰嶇疆锛岃吘璁簯娌℃湁acl鏉冮檺閰嶇疆锛� + //.acl(getAccessPolicy().getObjectCannedACL()) .build()) .build()); @@ -271,10 +240,11 @@ * * @param key 鏂囦欢鍦� Amazon S3 涓殑瀵硅薄閿� * @param out 杈撳嚭娴� + * @param consumer 鑷畾涔夊鐞嗛�昏緫 * @return 杈撳嚭娴佷腑鍐欏叆鐨勫瓧鑺傛暟锛堥暱搴︼級 * @throws OssException 濡傛灉涓嬭浇澶辫触锛屾姏鍑鸿嚜瀹氫箟寮傚父 */ - public long download(String key, OutputStream out) { + public void download(String key, OutputStream out, Consumer<Long> consumer) { try { // 鏋勫缓涓嬭浇璇锋眰 DownloadRequest<ResponseInputStream<GetObjectResponse>> downloadRequest = DownloadRequest.builder() @@ -290,7 +260,10 @@ Download<ResponseInputStream<GetObjectResponse>> responseFuture = transferManager.download(downloadRequest); // 杈撳嚭鍒版祦涓� try (ResponseInputStream<GetObjectResponse> responseStream = responseFuture.completionFuture().join().result()) { // auto-closeable stream - return responseStream.transferTo(out); // 闃诲璋冪敤绾跨▼ blocks the calling thread + if (consumer != null) { + consumer.accept(responseStream.response().contentLength()); + } + responseStream.transferTo(out); // 闃诲璋冪敤绾跨▼ blocks the calling thread } } catch (Exception e) { throw new OssException("鏂囦欢涓嬭浇澶辫触锛岄敊璇俊鎭�:[" + e.getMessage() + "]"); @@ -316,13 +289,13 @@ /** * 鑾峰彇绉佹湁URL閾炬帴 * - * @param objectKey 瀵硅薄KEY - * @param second 鎺堟潈鏃堕棿 + * @param objectKey 瀵硅薄KEY + * @param expiredTime 閾炬帴鎺堟潈鍒版湡鏃堕棿 */ - public String getPrivateUrl(String objectKey, Integer second) { + public String getPrivateUrl(String objectKey, Duration expiredTime) { // 浣跨敤 AWS S3 棰勭鍚� URL 鐨勭敓鎴愬櫒 鑾峰彇瀵硅薄鐨勯绛惧悕 URL URL url = presigner.presignGetObject( - x -> x.signatureDuration(Duration.ofSeconds(second)) + x -> x.signatureDuration(expiredTime) .getObjectRequest( y -> y.bucket(properties.getBucketName()) .key(objectKey) @@ -340,8 +313,8 @@ * @return UploadResult 鍖呭惈涓婁紶鍚庣殑鏂囦欢淇℃伅 * @throws OssException 濡傛灉涓婁紶澶辫触锛屾姏鍑鸿嚜瀹氫箟寮傚父 */ - public UploadResult uploadSuffix(byte[] data, String suffix) { - return upload(new ByteArrayInputStream(data), getPath(properties.getPrefix(), suffix), Long.valueOf(data.length), FileUtils.getMimeType(suffix)); + public UploadResult uploadSuffix(byte[] data, String suffix, String contentType) { + return upload(new ByteArrayInputStream(data), getPath(properties.getPrefix(), suffix), Long.valueOf(data.length), contentType); } /** @@ -353,8 +326,8 @@ * @return UploadResult 鍖呭惈涓婁紶鍚庣殑鏂囦欢淇℃伅 * @throws OssException 濡傛灉涓婁紶澶辫触锛屾姏鍑鸿嚜瀹氫箟寮傚父 */ - public UploadResult uploadSuffix(InputStream inputStream, String suffix, Long length) { - return upload(inputStream, getPath(properties.getPrefix(), suffix), length, FileUtils.getMimeType(suffix)); + public UploadResult uploadSuffix(InputStream inputStream, String suffix, Long length, String contentType) { + return upload(inputStream, getPath(properties.getPrefix(), suffix), length, contentType); } /** @@ -517,79 +490,6 @@ */ public AccessPolicyType getAccessPolicy() { return AccessPolicyType.getByType(properties.getAccessPolicy()); - } - - /** - * 鐢熸垚 AWS S3 瀛樺偍妗惰闂瓥鐣� - * - * @param bucketName 瀛樺偍妗� - * @param policyType 妗剁瓥鐣ョ被鍨� - * @return 绗﹀悎 AWS S3 瀛樺偍妗惰闂瓥鐣ユ牸寮忕殑瀛楃涓� - */ - private static String getPolicy(String bucketName, PolicyType policyType) { - String policy = switch (policyType) { - case WRITE -> """ - { - "Version": "2012-10-17", - "Statement": [] - } - """; - case READ_WRITE -> """ - { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Principal": "*", - "Action": [ - "s3:GetBucketLocation", - "s3:ListBucket", - "s3:ListBucketMultipartUploads" - ], - "Resource": "arn:aws:s3:::bucketName" - }, - { - "Effect": "Allow", - "Principal": "*", - "Action": [ - "s3:AbortMultipartUpload", - "s3:DeleteObject", - "s3:GetObject", - "s3:ListMultipartUploadParts", - "s3:PutObject" - ], - "Resource": "arn:aws:s3:::bucketName/*" - } - ] - } - """; - case READ -> """ - { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Principal": "*", - "Action": ["s3:GetBucketLocation"], - "Resource": "arn:aws:s3:::bucketName" - }, - { - "Effect": "Deny", - "Principal": "*", - "Action": ["s3:ListBucket"], - "Resource": "arn:aws:s3:::bucketName" - }, - { - "Effect": "Allow", - "Principal": "*", - "Action": "s3:GetObject", - "Resource": "arn:aws:s3:::bucketName/*" - } - ] - } - """; - }; - return policy.replaceAll("bucketName", bucketName); } } -- Gitblit v1.9.3